summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorDavid Vossel <dvossel@digium.com>2011-02-03 16:22:10 +0000
committerDavid Vossel <dvossel@digium.com>2011-02-03 16:22:10 +0000
commitc26c190711a1bbe3b5fff1a93facae333757c56e (patch)
tree00da0caa5a07b7b25729f089dbcafb08129fa9be /main
parent652fb64a01c7a8656697d07e606620ee0ced6929 (diff)
Asterisk media architecture conversion - no more format bitfields
This patch is the foundation of an entire new way of looking at media in Asterisk. The code present in this patch is everything required to complete phase1 of my Media Architecture proposal. For more information about this project visit the link below. https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal The primary function of this patch is to convert all the usages of format bitfields in Asterisk to use the new format and format_cap APIs. Functionally no change in behavior should be present in this patch. Thanks to twilson and russell for all the time they spent reviewing these changes. Review: https://reviewboard.asterisk.org/r/1083/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@306010 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/abstract_jb.c8
-rw-r--r--main/app.c24
-rw-r--r--main/asterisk.c9
-rw-r--r--main/astobj2.c37
-rw-r--r--main/audiohook.c32
-rw-r--r--main/bridging.c76
-rw-r--r--main/callerid.c20
-rw-r--r--main/ccss.c13
-rw-r--r--main/channel.c439
-rw-r--r--main/cli.c8
-rw-r--r--main/data.c33
-rw-r--r--main/dial.c16
-rw-r--r--main/dsp.c14
-rw-r--r--main/features.c40
-rw-r--r--main/file.c214
-rw-r--r--main/format.c558
-rw-r--r--main/format_cap.c545
-rw-r--r--main/format_pref.c320
-rw-r--r--main/frame.c424
-rw-r--r--main/image.c9
-rw-r--r--main/indications.c10
-rw-r--r--main/manager.c50
-rw-r--r--main/pbx.c12
-rw-r--r--main/rtp_engine.c435
-rw-r--r--main/slinfactory.c18
-rw-r--r--main/translate.c1168
-rw-r--r--main/udptl.c8
27 files changed, 3206 insertions, 1334 deletions
diff --git a/main/abstract_jb.c b/main/abstract_jb.c
index 4cd5ccb0d..5ff1c4b2a 100644
--- a/main/abstract_jb.c
+++ b/main/abstract_jb.c
@@ -398,7 +398,7 @@ static void jb_get_and_deliver(struct ast_channel *chan)
}
while (now >= jb->next) {
- interpolation_len = ast_codec_interp_len(jb->last_format);
+ interpolation_len = ast_codec_interp_len(&jb->last_format);
res = jbimpl->get(jbobj, &f, now, interpolation_len);
@@ -409,13 +409,13 @@ static void jb_get_and_deliver(struct ast_channel *chan)
case JB_IMPL_DROP:
jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
now, jb_get_actions[res], f->ts, f->len);
- jb->last_format = f->subclass.codec;
+ ast_format_copy(&jb->last_format, &f->subclass.format);
ast_frfree(f);
break;
case JB_IMPL_INTERP:
/* interpolate a frame */
f = &finterp;
- f->subclass.codec = jb->last_format;
+ ast_format_copy(&f->subclass.format, &jb->last_format);
f->samples = interpolation_len * 8;
f->src = "JB interpolation";
f->delivery = ast_tvadd(jb->timebase, ast_samp2tv(jb->next, 1000));
@@ -476,7 +476,7 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
jb->next = jbimpl->next(jbobj);
/* Init last format for a first time. */
- jb->last_format = frr->subclass.codec;
+ ast_format_copy(&jb->last_format, &frr->subclass.format);
/* Create a frame log file */
if (ast_test_flag(jbconf, AST_JB_LOG)) {
diff --git a/main/app.c b/main/app.c
index 0054c4cde..27858a29b 100644
--- a/main/app.c
+++ b/main/app.c
@@ -445,15 +445,15 @@ struct linear_state {
int fd;
int autoclose;
int allowoverride;
- int origwfmt;
+ struct ast_format origwfmt;
};
static void linear_release(struct ast_channel *chan, void *params)
{
struct linear_state *ls = params;
- if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
- ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
+ if (ls->origwfmt.id && ast_set_write_format(chan, &ls->origwfmt)) {
+ ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt.id);
}
if (ls->autoclose) {
@@ -469,12 +469,13 @@ static int linear_generator(struct ast_channel *chan, void *data, int len, int s
struct linear_state *ls = data;
struct ast_frame f = {
.frametype = AST_FRAME_VOICE,
- .subclass.codec = AST_FORMAT_SLINEAR,
.data.ptr = buf + AST_FRIENDLY_OFFSET / 2,
.offset = AST_FRIENDLY_OFFSET,
};
int res;
+ ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0);
+
len = samples * 2;
if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" , len);
@@ -507,9 +508,9 @@ static void *linear_alloc(struct ast_channel *chan, void *params)
ast_clear_flag(chan, AST_FLAG_WRITE_INT);
}
- ls->origwfmt = chan->writeformat;
+ ast_format_copy(&ls->origwfmt, &chan->writeformat);
- if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
+ if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
ast_free(ls);
ls = params = NULL;
@@ -741,10 +742,11 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
int totalsilence = 0;
int dspsilence = 0;
int olddspsilence = 0;
- int rfmt = 0;
+ struct ast_format rfmt;
struct ast_silence_generator *silgen = NULL;
char prependfile[80];
+ ast_format_clear(&rfmt);
if (silencethreshold < 0) {
silencethreshold = global_silence_threshold;
}
@@ -815,8 +817,8 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
return -1;
}
ast_dsp_set_threshold(sildet, silencethreshold);
- rfmt = chan->readformat;
- res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
+ ast_format_copy(&rfmt, &chan->readformat);
+ res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
ast_dsp_free(sildet);
@@ -1005,8 +1007,8 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
ast_filedelete(prependfile, sfmt[x]);
}
}
- if (rfmt && 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 (rfmt.id && 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 == 2) {
ast_stream_and_wait(chan, "auth-thankyou", "");
diff --git a/main/asterisk.c b/main/asterisk.c
index 8d81b5eed..7f8b6a285 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -111,6 +111,7 @@ int daemon(int, int); /* defined in libresolv of all places */
#include "asterisk/network.h"
#include "asterisk/cli.h"
#include "asterisk/channel.h"
+#include "asterisk/translate.h"
#include "asterisk/features.h"
#include "asterisk/ulaw.h"
#include "asterisk/alaw.h"
@@ -142,6 +143,7 @@ int daemon(int, int); /* defined in libresolv of all places */
#include "asterisk/poll-compat.h"
#include "asterisk/ccss.h"
#include "asterisk/test.h"
+#include "asterisk/format.h"
#include "asterisk/aoc.h"
#include "../defaults.h"
@@ -3669,6 +3671,11 @@ int main(int argc, char *argv[])
}
#endif
+ if (ast_translate_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
ast_aoc_cli_init();
ast_makesocket();
@@ -3700,6 +3707,8 @@ int main(int argc, char *argv[])
astobj2_init();
+ ast_format_attr_init();
+
ast_autoservice_init();
if (ast_timing_init()) {
diff --git a/main/astobj2.c b/main/astobj2.c
index ccfbf5388..6391844fe 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -137,7 +137,7 @@ enum ao2_callback_type {
static int internal_ao2_ref(void *user_data, const int delta);
static struct ao2_container *internal_ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn,
ao2_callback_fn *cmp_fn);
-static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func);
+static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, int flags, const char *file, int line, const char *func);
static void *internal_ao2_callback(struct ao2_container *c,
const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
char *tag, char *file, int line, const char *funcname);
@@ -471,7 +471,7 @@ struct bucket_entry {
* link an object to a container
*/
-static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
+static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, int flags, const char *file, int line, const char *func)
{
int i;
/* create a new list entry */
@@ -490,7 +490,9 @@ static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *use
i = abs(c->hash_fn(user_data, OBJ_POINTER));
- ao2_lock(c);
+ if (!(flags & OBJ_NOLOCK)) {
+ ao2_lock(c);
+ }
i %= c->n_buckets;
p->astobj = obj;
p->version = ast_atomic_fetchadd_int(&c->version, 1);
@@ -501,24 +503,28 @@ static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *use
return p;
}
-void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+void *__ao2_link_debug(struct ao2_container *c, void *user_data, int flags, char *tag, char *file, int line, const char *funcname)
{
- struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname);
+ struct bucket_entry *p = internal_ao2_link(c, user_data, flags, file, line, funcname);
if (p) {
__ao2_ref_debug(user_data, +1, tag, file, line, funcname);
- ao2_unlock(c);
+ if (!(flags & OBJ_NOLOCK)) {
+ ao2_unlock(c);
+ }
}
return p;
}
-void *__ao2_link(struct ao2_container *c, void *user_data)
+void *__ao2_link(struct ao2_container *c, void *user_data, int flags)
{
- struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+ struct bucket_entry *p = internal_ao2_link(c, user_data, flags, __FILE__, __LINE__, __PRETTY_FUNCTION__);
if (p) {
__ao2_ref(user_data, +1);
- ao2_unlock(c);
+ if (!(flags & OBJ_NOLOCK)) {
+ ao2_unlock(c);
+ }
}
return p;
}
@@ -535,23 +541,26 @@ int ao2_match_by_addr(void *user_data, void *arg, int flags)
* Unlink an object from the container
* and destroy the associated * bucket_entry structure.
*/
-void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
+void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags, char *tag,
char *file, int line, const char *funcname)
{
if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
return NULL;
- __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
+ flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
+
+ __ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, funcname);
return NULL;
}
-void *__ao2_unlink(struct ao2_container *c, void *user_data)
+void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags)
{
if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
return NULL;
- __ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
+ flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
+ __ao2_callback(c, flags, ao2_match_by_addr, user_data);
return NULL;
}
@@ -696,7 +705,7 @@ static void *internal_ao2_callback(struct ao2_container *c,
* link the object into the container that will hold the results.
*/
if (ret && (multi_container != NULL)) {
- __ao2_link(multi_container, ret);
+ __ao2_link(multi_container, ret, flags);
ret = NULL;
}
diff --git a/main/audiohook.c b/main/audiohook.c
index ad977ecbc..23650a79f 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -40,7 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
struct ast_audiohook_translate {
struct ast_trans_pvt *trans_pvt;
- format_t format;
+ struct ast_format format;
};
struct ast_audiohook_list {
@@ -185,11 +185,11 @@ static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audio
short buf[samples];
struct ast_frame frame = {
.frametype = AST_FRAME_VOICE,
- .subclass.codec = AST_FORMAT_SLINEAR,
.data.ptr = buf,
.datalen = sizeof(buf),
.samples = samples,
};
+ ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0);
/* Ensure the factory is able to give us the samples we want */
if (samples > ast_slinfactory_available(factory))
@@ -212,11 +212,11 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
struct ast_frame frame = {
.frametype = AST_FRAME_VOICE,
- .subclass.codec = AST_FORMAT_SLINEAR,
.data.ptr = NULL,
.datalen = sizeof(buf1),
.samples = samples,
};
+ ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0);
/* Make sure both factories have the required samples */
usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
@@ -304,23 +304,24 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
* \param format Format of frame remote side wants back
* \return Returns frame on success, NULL on failure
*/
-struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, format_t format)
+struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
{
struct ast_frame *read_frame = NULL, *final_frame = NULL;
+ struct ast_format tmp_fmt;
if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
return NULL;
/* If they don't want signed linear back out, we'll have to send it through the translation path */
- if (format != AST_FORMAT_SLINEAR) {
+ if (format->id != AST_FORMAT_SLINEAR) {
/* Rebuild translation path if different format then previously */
- if (audiohook->format != format) {
+ if (ast_format_cmp(format, &audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) {
if (audiohook->trans_pvt) {
ast_translator_free_path(audiohook->trans_pvt);
audiohook->trans_pvt = NULL;
}
/* Setup new translation path for this format... if we fail we can't very well return signed linear so free the frame and return nothing */
- if (!(audiohook->trans_pvt = ast_translator_build_path(format, AST_FORMAT_SLINEAR))) {
+ if (!(audiohook->trans_pvt = ast_translator_build_path(format, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0)))) {
ast_frfree(read_frame);
return NULL;
}
@@ -619,17 +620,18 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
struct ast_audiohook *audiohook = NULL;
+ struct ast_format tmp_fmt;
int samples = frame->samples;
/* ---Part_1. translate start_frame to SLINEAR if necessary. */
/* If the frame coming in is not signed linear we have to send it through the in_translate path */
- if (frame->subclass.codec != AST_FORMAT_SLINEAR) {
- if (in_translate->format != frame->subclass.codec) {
+ if (frame->subclass.format.id != AST_FORMAT_SLINEAR) {
+ if (ast_format_cmp(&frame->subclass.format, &in_translate->format) == AST_FORMAT_CMP_NOT_EQUAL) {
if (in_translate->trans_pvt)
ast_translator_free_path(in_translate->trans_pvt);
- if (!(in_translate->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, frame->subclass.codec)))
+ if (!(in_translate->trans_pvt = ast_translator_build_path(ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0), &frame->subclass.format)))
return frame;
- in_translate->format = frame->subclass.codec;
+ ast_format_copy(&in_translate->format, &frame->subclass.format);
}
if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
return frame;
@@ -707,16 +709,16 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
/* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
if (middle_frame == end_frame) {
/* Middle frame was modified and became the end frame... let's see if we need to transcode */
- if (end_frame->subclass.codec != start_frame->subclass.codec) {
- if (out_translate->format != start_frame->subclass.codec) {
+ if (ast_format_cmp(&end_frame->subclass.format, &start_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
+ if (ast_format_cmp(&out_translate->format, &start_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
if (out_translate->trans_pvt)
ast_translator_free_path(out_translate->trans_pvt);
- if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass.codec, AST_FORMAT_SLINEAR))) {
+ if (!(out_translate->trans_pvt = ast_translator_build_path(&start_frame->subclass.format, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0)))) {
/* We can't transcode this... drop our middle frame and return the original */
ast_frfree(middle_frame);
return start_frame;
}
- out_translate->format = start_frame->subclass.codec;
+ ast_format_copy(&out_translate->format, &start_frame->subclass.format);
}
/* Transcode from our middle (signed linear) frame to new format of the frame that came in */
if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
diff --git a/main/bridging.c b/main/bridging.c
index a256cf038..9de02aa34 100644
--- a/main/bridging.c
+++ b/main/bridging.c
@@ -382,16 +382,12 @@ static void *bridge_thread(void *data)
}
/*! \brief Helper function used to find the "best" bridge technology given a specified capabilities */
-static struct ast_bridge_technology *find_best_technology(format_t capabilities)
+static struct ast_bridge_technology *find_best_technology(uint32_t capabilities)
{
struct ast_bridge_technology *current = NULL, *best = NULL;
AST_RWLIST_RDLOCK(&bridge_technologies);
AST_RWLIST_TRAVERSE(&bridge_technologies, current, entry) {
- char tmp1[256], tmp2[256];
- ast_debug(1, "Bridge technology %s has capabilities %s and we want %s\n", current->name,
- ast_getformatname_multiple(tmp1, sizeof(tmp1), current->capabilities),
- ast_getformatname_multiple(tmp2, sizeof(tmp2), capabilities));
if (current->suspended) {
ast_debug(1, "Bridge technology %s is suspended. Skipping.\n", current->name);
continue;
@@ -448,7 +444,7 @@ static void destroy_bridge(void *obj)
return;
}
-struct ast_bridge *ast_bridge_new(format_t capabilities, int flags)
+struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags)
{
struct ast_bridge *bridge = NULL;
struct ast_bridge_technology *bridge_technology = NULL;
@@ -470,9 +466,6 @@ struct ast_bridge *ast_bridge_new(format_t capabilities, int flags)
/* If no bridge technology was found we can't possibly do bridging so fail creation of the bridge */
if (!bridge_technology) {
- char codec_buf[256];
- ast_debug(1, "Failed to find a bridge technology to satisfy capabilities %s\n",
- ast_getformatname_multiple(codec_buf, sizeof(codec_buf), capabilities));
return NULL;
}
@@ -503,7 +496,7 @@ struct ast_bridge *ast_bridge_new(format_t capabilities, int flags)
return bridge;
}
-int ast_bridge_check(format_t capabilities)
+int ast_bridge_check(uint32_t capabilities)
{
struct ast_bridge_technology *bridge_technology = NULL;
@@ -542,47 +535,51 @@ int ast_bridge_destroy(struct ast_bridge *bridge)
static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
- format_t formats[2] = {bridge_channel->chan->readformat, bridge_channel->chan->writeformat};
+ struct ast_format formats[2];
+ ast_format_copy(&formats[0], &bridge_channel->chan->readformat);
+ ast_format_copy(&formats[1], &bridge_channel->chan->writeformat);
/* Are the formats currently in use something ths bridge can handle? */
- if (!(bridge->technology->formats & bridge_channel->chan->readformat)) {
- format_t best_format = ast_best_codec(bridge->technology->formats);
+ if (!ast_format_cap_iscompatible(bridge->technology->format_capabilities, &bridge_channel->chan->readformat)) {
+ struct ast_format best_format;
+ ast_best_codec(bridge->technology->format_capabilities, &best_format);
/* Read format is a no go... */
if (option_debug) {
char codec_buf[512];
ast_debug(1, "Bridge technology %s wants to read any of formats %s but channel has %s\n", bridge->technology->name,
- ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->formats),
- ast_getformatname(formats[0]));
+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->format_capabilities),
+ ast_getformatname(&formats[0]));
}
/* Switch read format to the best one chosen */
- if (ast_set_read_format(bridge_channel->chan, best_format)) {
- ast_log(LOG_WARNING, "Failed to set channel %s to read format %s\n", bridge_channel->chan->name, ast_getformatname(best_format));
+ if (ast_set_read_format(bridge_channel->chan, &best_format)) {
+ ast_log(LOG_WARNING, "Failed to set channel %s to read format %s\n", bridge_channel->chan->name, ast_getformatname(&best_format));
return -1;
}
- ast_debug(1, "Bridge %p put channel %s into read format %s\n", bridge, bridge_channel->chan->name, ast_getformatname(best_format));
+ ast_debug(1, "Bridge %p put channel %s into read format %s\n", bridge, bridge_channel->chan->name, ast_getformatname(&best_format));
} else {
- ast_debug(1, "Bridge %p is happy that channel %s already has read format %s\n", bridge, bridge_channel->chan->name, ast_getformatname(formats[0]));
+ ast_debug(1, "Bridge %p is happy that channel %s already has read format %s\n", bridge, bridge_channel->chan->name, ast_getformatname(&formats[0]));
}
- if (!(bridge->technology->formats & formats[1])) {
- int best_format = ast_best_codec(bridge->technology->formats);
+ if (!ast_format_cap_iscompatible(bridge->technology->format_capabilities, &formats[1])) {
+ struct ast_format best_format;
+ ast_best_codec(bridge->technology->format_capabilities, &best_format);
/* Write format is a no go... */
if (option_debug) {
char codec_buf[512];
ast_debug(1, "Bridge technology %s wants to write any of formats %s but channel has %s\n", bridge->technology->name,
- ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->formats),
- ast_getformatname(formats[1]));
+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf), bridge->technology->format_capabilities),
+ ast_getformatname(&formats[1]));
}
/* Switch write format to the best one chosen */
- if (ast_set_write_format(bridge_channel->chan, best_format)) {
- ast_log(LOG_WARNING, "Failed to set channel %s to write format %s\n", bridge_channel->chan->name, ast_getformatname(best_format));
+ if (ast_set_write_format(bridge_channel->chan, &best_format)) {
+ ast_log(LOG_WARNING, "Failed to set channel %s to write format %s\n", bridge_channel->chan->name, ast_getformatname(&best_format));
return -1;
}
- ast_debug(1, "Bridge %p put channel %s into write format %s\n", bridge, bridge_channel->chan->name, ast_getformatname(best_format));
+ ast_debug(1, "Bridge %p put channel %s into write format %s\n", bridge, bridge_channel->chan->name, ast_getformatname(&best_format));
} else {
- ast_debug(1, "Bridge %p is happy that channel %s already has write format %s\n", bridge, bridge_channel->chan->name, ast_getformatname(formats[1]));
+ ast_debug(1, "Bridge %p is happy that channel %s already has write format %s\n", bridge, bridge_channel->chan->name, ast_getformatname(&formats[1]));
}
return 0;
@@ -591,7 +588,7 @@ static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_c
/*! \brief Perform the smart bridge operation. Basically sees if a new bridge technology should be used instead of the current one. */
static int smart_bridge_operation(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int count)
{
- format_t new_capabilities = 0;
+ uint32_t new_capabilities = 0;
struct ast_bridge_technology *new_technology = NULL, *old_technology = bridge->technology;
struct ast_bridge temp_bridge = {
.technology = bridge->technology,
@@ -621,9 +618,6 @@ static int smart_bridge_operation(struct ast_bridge *bridge, struct ast_bridge_c
/* Attempt to find a new bridge technology to satisfy the capabilities */
if (!(new_technology = find_best_technology(new_capabilities))) {
- char codec_buf[256];
- ast_debug(1, "Smart bridge operation was unable to find new bridge technology with capabilities %s to satisfy bridge %p\n",
- ast_getformatname_multiple(codec_buf, sizeof(codec_buf), new_capabilities), bridge);
return -1;
}
@@ -873,8 +867,10 @@ static void bridge_channel_dtmf_stream(struct ast_bridge *bridge, struct ast_bri
/*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge_channel *bridge_channel)
{
- int formats[2] = { bridge_channel->chan->readformat, bridge_channel->chan->writeformat };
+ struct ast_format formats[2];
enum ast_bridge_channel_state state;
+ ast_format_copy(&formats[0], &bridge_channel->chan->readformat);
+ ast_format_copy(&formats[1], &bridge_channel->chan->writeformat);
/* Record the thread that will be the owner of us */
bridge_channel->thread = pthread_self();
@@ -975,16 +971,16 @@ static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge_chann
ao2_unlock(bridge_channel->bridge);
/* Restore original formats of the channel as they came in */
- if (bridge_channel->chan->readformat != formats[0]) {
- ast_debug(1, "Bridge is returning %p to read format %s(%d)\n", bridge_channel, ast_getformatname(formats[0]), formats[0]);
- if (ast_set_read_format(bridge_channel->chan, formats[0])) {
- ast_debug(1, "Bridge failed to return channel %p to read format %s(%d)\n", bridge_channel, ast_getformatname(formats[0]), formats[0]);
+ if (ast_format_cmp(&bridge_channel->chan->readformat, &formats[0]) == AST_FORMAT_CMP_NOT_EQUAL) {
+ ast_debug(1, "Bridge is returning %p to read format %s(%d)\n", bridge_channel, ast_getformatname(&formats[0]), formats[0].id);
+ if (ast_set_read_format(bridge_channel->chan, &formats[0])) {
+ ast_debug(1, "Bridge failed to return channel %p to read format %s(%d)\n", bridge_channel, ast_getformatname(&formats[0]), formats[0].id);
}
}
- if (bridge_channel->chan->writeformat != formats[1]) {
- ast_debug(1, "Bridge is returning %p to write format %s(%d)\n", bridge_channel, ast_getformatname(formats[1]), formats[1]);
- if (ast_set_write_format(bridge_channel->chan, formats[1])) {
- ast_debug(1, "Bridge failed to return channel %p to write format %s(%d)\n", bridge_channel, ast_getformatname(formats[1]), formats[1]);
+ if (ast_format_cmp(&bridge_channel->chan->writeformat, &formats[1]) == AST_FORMAT_CMP_NOT_EQUAL) {
+ ast_debug(1, "Bridge is returning %p to write format %s(%d)\n", bridge_channel, ast_getformatname(&formats[1]), formats[1].id);
+ if (ast_set_write_format(bridge_channel->chan, &formats[1])) {
+ ast_debug(1, "Bridge failed to return channel %p to write format %s(%d)\n", bridge_channel, ast_getformatname(&formats[1]), formats[1].id);
}
}
diff --git a/main/callerid.c b/main/callerid.c
index ac8fbde8b..aa53eb83e 100644
--- a/main/callerid.c
+++ b/main/callerid.c
@@ -71,7 +71,7 @@ float casdr1, casdi1, casdr2, casdi2;
#define AST_CALLERID_UNKNOWN "<unknown>"
-static inline void gen_tones(unsigned char *buf, int len, format_t codec, float ddr1, float ddi1, float ddr2, float ddi2, float *cr1, float *ci1, float *cr2, float *ci2)
+static inline void gen_tones(unsigned char *buf, int len, struct ast_format *codec, float ddr1, float ddi1, float ddr2, float ddi2, float *cr1, float *ci1, float *cr2, float *ci2)
{
int x;
float t;
@@ -93,7 +93,7 @@ static inline void gen_tones(unsigned char *buf, int len, format_t codec, float
}
}
-static inline void gen_tone(unsigned char *buf, int len, format_t codec, float ddr1, float ddi1, float *cr1, float *ci1)
+static inline void gen_tone(unsigned char *buf, int len, struct ast_format *codec, float ddr1, float ddi1, float *cr1, float *ci1)
{
int x;
float t;
@@ -255,7 +255,7 @@ void callerid_get_dtmf(char *cidstring, char *number, int *flags)
}
}
-int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, format_t codec)
+int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, struct ast_format *codec)
{
int pos = 0;
int saslen = 2400;
@@ -300,7 +300,7 @@ static unsigned short calc_crc(unsigned short crc, unsigned char data)
return crc;
}
-int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec)
+int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, struct ast_format *codec)
{
int mylen = len;
int olen;
@@ -539,7 +539,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, f
}
-int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec)
+int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, struct ast_format *codec)
{
int mylen = len;
int olen;
@@ -791,7 +791,7 @@ static int callerid_genmsg(char *msg, int size, const char *number, const char *
}
-int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, format_t codec,
+int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, struct ast_format *codec,
const char* name, const char* number, int flags)
{
char msg[256];
@@ -879,7 +879,7 @@ int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, format_
return bytes;
}
-int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, format_t codec)
+int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, struct ast_format *codec)
{
int bytes = 0;
int x, sum;
@@ -1038,7 +1038,7 @@ int ast_callerid_parse(char *instr, char **name, char **location)
return 0;
}
-static int __ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int callwaiting, format_t codec)
+static int __ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int callwaiting, struct ast_format *codec)
{
if (ast_strlen_zero(name))
name = NULL;
@@ -1047,12 +1047,12 @@ static int __ast_callerid_generate(unsigned char *buf, const char *name, const c
return callerid_generate(buf, number, name, 0, callwaiting, codec);
}
-int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, format_t codec)
+int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, struct ast_format *codec)
{
return __ast_callerid_generate(buf, name, number, 0, codec);
}
-int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, format_t codec)
+int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, struct ast_format *codec)
{
return __ast_callerid_generate(buf, name, number, 1, codec);
}
diff --git a/main/ccss.c b/main/ccss.c
index 3583e8472..fc79a01dd 100644
--- a/main/ccss.c
+++ b/main/ccss.c
@@ -2482,19 +2482,30 @@ static void *generic_recall(void *data)
struct ast_channel *chan;
const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
+ struct ast_format tmp_fmt;
+ struct ast_format_cap *tmp_cap = ast_format_cap_alloc_nolock();
+
+ if (!tmp_cap) {
+ return NULL;
+ }
tech = interface;
if ((target = strchr(interface, '/'))) {
*target++ = '\0';
}
- if (!(chan = ast_request_and_dial(tech, AST_FORMAT_SLINEAR, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
+
+ ast_format_cap_add(tmp_cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
+ if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
/* Hmm, no channel. Sucks for you, bud.
*/
ast_log_dynamic_level(cc_logger_level, "Core %d: Failed to call back %s for reason %d\n",
agent->core_id, agent->device_name, reason);
ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
+ ast_format_cap_destroy(tmp_cap);
return NULL;
}
+ ast_format_cap_destroy(tmp_cap);
+
if (!ast_strlen_zero(callback_macro)) {
ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback macro configured for agent %s\n",
agent->core_id, agent->device_name);
diff --git a/main/channel.c b/main/channel.c
index 0cabf2d7e..796dc8b01 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -372,12 +372,12 @@ int ast_channel_data_add_structure(struct ast_data *tree,
}
}
- ast_data_add_codecs(tree, "oldwriteformat", chan->oldwriteformat);
+ ast_data_add_codec(tree, "oldwriteformat", &chan->oldwriteformat);
+ ast_data_add_codec(tree, "readformat", &chan->readformat);
+ ast_data_add_codec(tree, "writeformat", &chan->writeformat);
+ ast_data_add_codec(tree, "rawreadformat", &chan->rawreadformat);
+ ast_data_add_codec(tree, "rawwriteformat", &chan->rawwriteformat);
ast_data_add_codecs(tree, "nativeformats", chan->nativeformats);
- ast_data_add_codecs(tree, "readformat", chan->readformat);
- ast_data_add_codecs(tree, "writeformat", chan->writeformat);
- ast_data_add_codecs(tree, "rawreadformat", chan->rawreadformat);
- ast_data_add_codecs(tree, "rawwriteformat", chan->rawwriteformat);
/* state */
enum_node = ast_data_add_node(tree, "state");
@@ -593,7 +593,7 @@ static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd,
(cl->tech->devicestate) ? "yes" : "no",
(cl->tech->indicate) ? "yes" : "no",
(cl->tech->transfer) ? "yes" : "no",
- ast_getformatname_multiple(buf, sizeof(buf), (cl->tech->capabilities) ? cl->tech->capabilities : -1),
+ ast_getformatname_multiple(buf, sizeof(buf), cl->tech->capabilities),
(cl->tech->send_digit_begin) ? "yes" : "no",
(cl->tech->send_digit_end) ? "yes" : "no",
(cl->tech->send_html) ? "yes" : "no",
@@ -989,12 +989,11 @@ char *ast_transfercapability2str(int transfercapability)
}
/*! \brief Pick the best audio codec */
-format_t ast_best_codec(format_t fmts)
+struct ast_format *ast_best_codec(struct ast_format_cap *cap, struct ast_format *result)
{
/* This just our opinion, expressed in code. We are asked to choose
the best codec to use, given no information */
- int x;
- static const format_t prefs[] =
+ static const enum ast_format_id prefs[] =
{
/*! Okay, ulaw is used by all telephony equipment, so start with it */
AST_FORMAT_ULAW,
@@ -1032,19 +1031,19 @@ format_t ast_best_codec(format_t fmts)
AST_FORMAT_G723_1,
};
char buf[512];
+ int x;
- /* Strip out video */
- fmts &= AST_FORMAT_AUDIO_MASK;
-
/* Find the first preferred codec in the format given */
for (x = 0; x < ARRAY_LEN(prefs); x++) {
- if (fmts & prefs[x])
- return prefs[x];
+ if (ast_format_cap_iscompatible(cap, ast_format_set(result, prefs[x], 0))) {
+ return result;
+ }
}
- ast_log(LOG_WARNING, "Don't know any of %s formats\n", ast_getformatname_multiple(buf, sizeof(buf), fmts));
+ ast_format_clear(result);
+ ast_log(LOG_WARNING, "Don't know any of %s formats\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
- return 0;
+ return NULL;
}
static const struct ast_channel_tech null_tech = {
@@ -1087,6 +1086,11 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
/* Channel structure allocation failure. */
return NULL;
}
+ if (!(tmp->nativeformats = ast_format_cap_alloc())) {
+ ao2_ref(tmp, -1);
+ /* format capabilities structure allocation failure */
+ return NULL;
+ }
/*
* Init file descriptors to unopened state so
@@ -2426,6 +2430,8 @@ static void ast_channel_destructor(void *obj)
*/
ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name);
}
+
+ chan->nativeformats = ast_format_cap_destroy(chan->nativeformats);
}
/*! \brief Free a dummy channel structure */
@@ -2658,8 +2664,15 @@ static void free_translation(struct ast_channel *clonechan)
ast_translator_free_path(clonechan->readtrans);
clonechan->writetrans = NULL;
clonechan->readtrans = NULL;
- clonechan->rawwriteformat = clonechan->nativeformats;
- clonechan->rawreadformat = clonechan->nativeformats;
+ if (ast_format_cap_is_empty(clonechan->nativeformats)) {
+ ast_format_clear(&clonechan->rawwriteformat);
+ ast_format_clear(&clonechan->rawreadformat);
+ } else {
+ struct ast_format tmpfmt;
+ ast_best_codec(clonechan->nativeformats, &tmpfmt);
+ ast_format_copy(&clonechan->rawwriteformat, &tmpfmt);
+ ast_format_copy(&clonechan->rawreadformat, &tmpfmt);
+ }
}
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
@@ -2987,7 +3000,7 @@ static int generator_force(const void *data)
if (!tmp || !generate)
return 0;
- res = generate(chan, tmp, 0, ast_format_rate(chan->writeformat & AST_FORMAT_AUDIO_MASK) / 50);
+ res = generate(chan, tmp, 0, ast_format_rate(&chan->writeformat) / 50);
chan->generatordata = tmp;
@@ -3548,9 +3561,9 @@ static void ast_read_generator_actions(struct ast_channel *chan, struct ast_fram
chan->generatordata = NULL; /* reset, to let writes go through */
- if (f->subclass.codec != chan->writeformat) {
+ if (ast_format_cmp(&f->subclass.format, &chan->writeformat) == AST_FORMAT_CMP_NOT_EQUAL) {
float factor;
- factor = ((float) ast_format_rate(chan->writeformat)) / ((float) ast_format_rate(f->subclass.codec));
+ factor = ((float) ast_format_rate(&chan->writeformat)) / ((float) ast_format_rate(&f->subclass.format));
samples = (int) ( ((float) f->samples) * factor );
} else {
samples = f->samples;
@@ -4066,11 +4079,11 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
ast_frfree(f);
f = &ast_null_frame;
}
- } else if ((f->frametype == AST_FRAME_VOICE) && !(f->subclass.codec & chan->nativeformats)) {
+ } else if ((f->frametype == AST_FRAME_VOICE) && !ast_format_cap_iscompatible(chan->nativeformats, &f->subclass.format)) {
/* This frame is not one of the current native formats -- drop it on the floor */
char to[200];
ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n",
- chan->name, ast_getformatname(f->subclass.codec), ast_getformatname_multiple(to, sizeof(to), chan->nativeformats));
+ chan->name, ast_getformatname(&f->subclass.format), ast_getformatname_multiple(to, sizeof(to), chan->nativeformats));
ast_frfree(f);
f = &ast_null_frame;
} else if ((f->frametype == AST_FRAME_VOICE)) {
@@ -4086,7 +4099,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
#ifndef MONITOR_CONSTANT_DELAY
int jump = chan->outsmpl - chan->insmpl - 4 * f->samples;
if (jump >= 0) {
- jump = calc_monitor_jump((chan->outsmpl - chan->insmpl), ast_format_rate(f->subclass.codec), ast_format_rate(chan->monitor->read_stream->fmt->format));
+ jump = calc_monitor_jump((chan->outsmpl - chan->insmpl), ast_format_rate(&f->subclass.format), ast_format_rate(&chan->monitor->read_stream->fmt->format));
if (ast_seekstream(chan->monitor->read_stream, jump, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
chan->insmpl += (chan->outsmpl - chan->insmpl) + f->samples;
@@ -4557,7 +4570,7 @@ int ast_prod(struct ast_channel *chan)
/* Send an empty audio frame to get things moving */
if (chan->_state != AST_STATE_UP) {
ast_debug(1, "Prodding channel '%s'\n", chan->name);
- a.subclass.codec = chan->rawwriteformat;
+ ast_format_copy(&a.subclass.format, &chan->rawwriteformat);
a.data.ptr = nothing + AST_FRIENDLY_OFFSET;
a.src = "ast_prod"; /* this better match check in ast_write */
if (ast_write(chan, &a))
@@ -4808,12 +4821,12 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
if (chan->tech->write == NULL)
break; /*! \todo XXX should return 0 maybe ? */
- if (ast_opt_generic_plc && fr->subclass.codec == AST_FORMAT_SLINEAR) {
+ if (ast_opt_generic_plc && fr->subclass.format.id == AST_FORMAT_SLINEAR) {
apply_plc(chan, fr);
}
/* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
- if (fr->subclass.codec == chan->rawwriteformat)
+ if (ast_format_cmp(&fr->subclass.format, &chan->rawwriteformat) != AST_FORMAT_CMP_NOT_EQUAL)
f = fr;
else
f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr;
@@ -4880,7 +4893,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
#ifndef MONITOR_CONSTANT_DELAY
int jump = chan->insmpl - chan->outsmpl - 4 * cur->samples;
if (jump >= 0) {
- jump = calc_monitor_jump((chan->insmpl - chan->outsmpl), ast_format_rate(f->subclass.codec), ast_format_rate(chan->monitor->read_stream->fmt->format));
+ jump = calc_monitor_jump((chan->insmpl - chan->outsmpl), ast_format_rate(&f->subclass.format), ast_format_rate(&chan->monitor->read_stream->fmt->format));
if (ast_seekstream(chan->monitor->write_stream, jump, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
chan->outsmpl += (chan->insmpl - chan->outsmpl) + cur->samples;
@@ -4967,26 +4980,33 @@ done:
return res;
}
-static int set_format(struct ast_channel *chan, format_t fmt, format_t *rawformat, format_t *format,
- struct ast_trans_pvt **trans, const int direction)
+static int set_format(struct ast_channel *chan,
+ struct ast_format_cap *cap_set,
+ struct ast_format *rawformat,
+ struct ast_format *format,
+ struct ast_trans_pvt **trans,
+ const int direction)
{
- format_t native, native_fmt = ast_best_codec(fmt);
+ struct ast_format_cap *cap_native = chan->nativeformats;
+ struct ast_format best_set_fmt;
+ struct ast_format best_native_fmt;
int res;
char from[200], to[200];
-
- /* Make sure we only consider audio */
- fmt &= AST_FORMAT_AUDIO_MASK;
-
- native = chan->nativeformats;
- if (!fmt || !native) /* No audio requested */
- return 0; /* Let's try a call without any sounds (video, text) */
+ ast_best_codec(cap_set, &best_set_fmt);
/* See if the underlying channel driver is capable of performing transcoding for us */
- if (!ast_channel_setoption(chan, direction ? AST_OPTION_FORMAT_WRITE : AST_OPTION_FORMAT_READ, &native_fmt, sizeof(int*), 0)) {
+ if (!ast_channel_setoption(chan, direction ? AST_OPTION_FORMAT_WRITE : AST_OPTION_FORMAT_READ, &best_set_fmt, sizeof(best_set_fmt), 0)) {
ast_debug(1, "Channel driver natively set channel %s to %s format %s\n", chan->name,
- direction ? "write" : "read", ast_getformatname(native_fmt));
- chan->nativeformats = *rawformat = *format = native_fmt;
+ direction ? "write" : "read", ast_getformatname(&best_set_fmt));
+
+ ast_format_copy(format, &best_set_fmt);
+ ast_format_copy(rawformat, &best_set_fmt);
+
+ ast_channel_lock(chan);
+ ast_format_cap_set(chan->nativeformats, &best_set_fmt);
+ ast_channel_unlock(chan);
+
if (*trans) {
ast_translator_free_path(*trans);
}
@@ -4995,39 +5015,44 @@ static int set_format(struct ast_channel *chan, format_t fmt, format_t *rawforma
}
/* Find a translation path from the native format to one of the desired formats */
- if (!direction)
+ if (!direction) {
/* reading */
- res = ast_translator_best_choice(&fmt, &native);
- else
+ res = ast_translator_best_choice(cap_set, cap_native, &best_set_fmt, &best_native_fmt);
+ } else {
/* writing */
- res = ast_translator_best_choice(&native, &fmt);
+ res = ast_translator_best_choice(cap_native, cap_set, &best_native_fmt, &best_set_fmt);
+ }
if (res < 0) {
ast_log(LOG_WARNING, "Unable to find a codec translation path from %s to %s\n",
- ast_getformatname_multiple(from, sizeof(from), native),
- ast_getformatname_multiple(to, sizeof(to), fmt));
+ ast_getformatname_multiple(from, sizeof(from), cap_native),
+ ast_getformatname_multiple(to, sizeof(to), cap_set));
return -1;
}
-
+
/* Now we have a good choice for both. */
ast_channel_lock(chan);
- if ((*rawformat == native) && (*format == fmt) && ((*rawformat == *format) || (*trans))) {
+ if ((ast_format_cmp(rawformat, &best_native_fmt) != AST_FORMAT_CMP_NOT_EQUAL) &&
+ (ast_format_cmp(format, &best_set_fmt) != AST_FORMAT_CMP_NOT_EQUAL) &&
+ ((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || (*trans))) {
/* the channel is already in these formats, so nothing to do */
ast_channel_unlock(chan);
return 0;
}
- *rawformat = native;
+ ast_format_copy(rawformat, &best_native_fmt);
/* User perspective is fmt */
- *format = fmt;
+ ast_format_copy(format, &best_set_fmt);
+
/* Free any read translation we have right now */
if (*trans) {
ast_translator_free_path(*trans);
*trans = NULL;
}
+
/* Build a translation path from the raw format to the desired format */
- if (*format == *rawformat) {
+ if (ast_format_cmp(format, rawformat) != AST_FORMAT_CMP_NOT_EQUAL) {
/*
* If we were able to swap the native format to the format that
* has been requested, then there is no need to try to build
@@ -5037,29 +5062,122 @@ static int set_format(struct ast_channel *chan, format_t fmt, format_t *rawforma
} else {
if (!direction) {
/* reading */
- *trans = ast_translator_build_path(*format, *rawformat);
+ *trans = ast_translator_build_path(format, rawformat);
} else {
/* writing */
- *trans = ast_translator_build_path(*rawformat, *format);
+ *trans = ast_translator_build_path(rawformat, format);
}
res = *trans ? 0 : -1;
}
ast_channel_unlock(chan);
- ast_debug(1, "Set channel %s to %s format %s\n", chan->name,
- direction ? "write" : "read", ast_getformatname(fmt));
+
+ ast_debug(1, "Set channel %s to %s format %s\n",
+ chan->name,
+ direction ? "write" : "read",
+ ast_getformatname(&best_set_fmt));
+ return res;
+}
+
+int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
+{
+ struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+ int res;
+ if (!cap) {
+ return -1;
+ }
+ ast_format_cap_add(cap, format);
+
+ res = set_format(chan,
+ cap,
+ &chan->rawreadformat,
+ &chan->readformat,
+ &chan->readtrans,
+ 0);
+
+ ast_format_cap_destroy(cap);
return res;
}
-int ast_set_read_format(struct ast_channel *chan, format_t fmt)
+int ast_set_read_format_by_id(struct ast_channel *chan, enum ast_format_id id)
{
- return set_format(chan, fmt, &chan->rawreadformat, &chan->readformat,
- &chan->readtrans, 0);
+ struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+ struct ast_format tmp_format;
+ int res;
+ if (!cap) {
+ return -1;
+ }
+ ast_format_cap_add(cap, ast_format_set(&tmp_format, id, 0));
+
+ res = set_format(chan,
+ cap,
+ &chan->rawreadformat,
+ &chan->readformat,
+ &chan->readtrans,
+ 0);
+
+ ast_format_cap_destroy(cap);
+ return res;
}
-int ast_set_write_format(struct ast_channel *chan, format_t fmt)
+int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap)
{
- return set_format(chan, fmt, &chan->rawwriteformat, &chan->writeformat,
- &chan->writetrans, 1);
+ return set_format(chan,
+ cap,
+ &chan->rawreadformat,
+ &chan->readformat,
+ &chan->readtrans,
+ 0);
+}
+
+int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
+{
+ struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+ int res;
+ if (!cap) {
+ return -1;
+ }
+ ast_format_cap_add(cap, format);
+
+ res = set_format(chan,
+ cap,
+ &chan->rawwriteformat,
+ &chan->writeformat,
+ &chan->writetrans,
+ 1);
+
+ ast_format_cap_destroy(cap);
+ return res;
+}
+
+int ast_set_write_format_by_id(struct ast_channel *chan, enum ast_format_id id)
+{
+ struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+ struct ast_format tmp_format;
+ int res;
+ if (!cap) {
+ return -1;
+ }
+ ast_format_cap_add(cap, ast_format_set(&tmp_format, id, 0));
+
+ res = set_format(chan,
+ cap,
+ &chan->rawwriteformat,
+ &chan->writeformat,
+ &chan->writetrans,
+ 1);
+
+ ast_format_cap_destroy(cap);
+ return res;
+}
+
+int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap)
+{
+ return set_format(chan,
+ cap,
+ &chan->rawwriteformat,
+ &chan->writeformat,
+ &chan->writetrans,
+ 1);
}
const char *ast_channel_reason2str(int reason)
@@ -5098,7 +5216,7 @@ static void handle_cause(int cause, int *outstate)
}
}
-struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, format_t format, struct outgoing_helper *oh, int *outstate)
+struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, struct ast_format_cap *cap, struct outgoing_helper *oh, int *outstate)
{
char tmpchan[256];
struct ast_channel *new = NULL;
@@ -5121,7 +5239,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
data = tmpchan;
type = "Local";
}
- if (!(new = ast_request(type, format, orig, data, &cause))) {
+ if (!(new = ast_request(type, cap, orig, data, &cause))) {
ast_log(LOG_NOTICE, "Unable to create channel for call forward to '%s/%s' (cause = %d)\n", type, data, cause);
handle_cause(cause, outstate);
ast_hangup(orig);
@@ -5179,7 +5297,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
return new;
}
-struct ast_channel *__ast_request_and_dial(const char *type, format_t format, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
+struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
{
int dummy_outstate;
int cause = 0;
@@ -5193,7 +5311,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co
else
outstate = &dummy_outstate; /* make outstate always a valid pointer */
- chan = ast_request(type, format, requestor, data, &cause);
+ chan = ast_request(type, cap, requestor, data, &cause);
if (!chan) {
ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
handle_cause(cause, outstate);
@@ -5245,7 +5363,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co
if (timeout > -1)
timeout = res;
if (!ast_strlen_zero(chan->call_forward)) {
- if (!(chan = ast_call_forward(NULL, chan, NULL, format, oh, outstate))) {
+ if (!(chan = ast_call_forward(NULL, chan, NULL, cap, oh, outstate))) {
return NULL;
}
continue;
@@ -5338,9 +5456,9 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co
return chan;
}
-struct ast_channel *ast_request_and_dial(const char *type, format_t format, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname)
+struct ast_channel *ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname)
{
- return __ast_request_and_dial(type, format, requestor, data, timeout, outstate, cidnum, cidname, NULL);
+ return __ast_request_and_dial(type, cap, requestor, data, timeout, outstate, cidnum, cidname, NULL);
}
static int set_security_requirements(const struct ast_channel *requestor, struct ast_channel *out)
@@ -5383,16 +5501,12 @@ static int set_security_requirements(const struct ast_channel *requestor, struct
return 0;
}
-struct ast_channel *ast_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
+struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_channel *requestor, void *data, int *cause)
{
struct chanlist *chan;
struct ast_channel *c;
- format_t capabilities;
- format_t fmt;
int res;
int foo;
- format_t videoformat = format & AST_FORMAT_VIDEO_MASK;
- format_t textformat = format & AST_FORMAT_TEXT_MASK;
if (!cause)
cause = &foo;
@@ -5404,21 +5518,27 @@ struct ast_channel *ast_request(const char *type, format_t format, const struct
}
AST_RWLIST_TRAVERSE(&backends, chan, list) {
+ struct ast_format_cap *tmp_cap;
+ struct ast_format tmp_fmt;
+ struct ast_format best_audio_fmt;
+ struct ast_format_cap *joint_cap;
+
if (strcasecmp(type, chan->tech->type))
continue;
- capabilities = chan->tech->capabilities;
- fmt = format & AST_FORMAT_AUDIO_MASK;
- if (fmt) {
+ ast_format_clear(&best_audio_fmt);
+ /* find the best audio format to use */
+ if ((tmp_cap = ast_format_cap_get_type(request_cap, AST_FORMAT_TYPE_AUDIO))) {
/* We have audio - is it possible to connect the various calls to each other?
(Avoid this check for calls without audio, like text+video calls)
*/
- res = ast_translator_best_choice(&fmt, &capabilities);
+ res = ast_translator_best_choice(tmp_cap, chan->tech->capabilities, &tmp_fmt, &best_audio_fmt);
+ ast_format_cap_destroy(tmp_cap);
if (res < 0) {
char tmp1[256], tmp2[256];
ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type,
ast_getformatname_multiple(tmp1, sizeof(tmp1), chan->tech->capabilities),
- ast_getformatname_multiple(tmp2, sizeof(tmp2), format));
+ ast_getformatname_multiple(tmp2, sizeof(tmp2), request_cap));
*cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
AST_RWLIST_UNLOCK(&backends);
return NULL;
@@ -5428,8 +5548,21 @@ struct ast_channel *ast_request(const char *type, format_t format, const struct
if (!chan->tech->requester)
return NULL;
- if (!(c = chan->tech->requester(type, capabilities | videoformat | textformat, requestor, data, cause)))
+ /* XXX Only the audio format calculated as being the best for translation
+ * purposes is used for the request. This needs to be re-evaluated. It may be
+ * a better choice to send all the audio formats capable of being translated
+ * during the request and allow the channel drivers to pick the best one. */
+ if (!(joint_cap = ast_format_cap_dup(request_cap))) {
return NULL;
+ }
+ ast_format_cap_remove_bytype(joint_cap, AST_FORMAT_TYPE_AUDIO);
+ ast_format_cap_add(joint_cap, &best_audio_fmt);
+
+ if (!(c = chan->tech->requester(type, joint_cap, requestor, data, cause))) {
+ ast_format_cap_destroy(joint_cap);
+ return NULL;
+ }
+ joint_cap = ast_format_cap_destroy(joint_cap);
if (set_security_requirements(requestor, c)) {
ast_log(LOG_WARNING, "Setting security requirements failed\n");
@@ -5610,7 +5743,10 @@ int ast_channel_sendurl(struct ast_channel *chan, const char *url)
/*! \brief Set up translation from one channel to another */
static int ast_channel_make_compatible_helper(struct ast_channel *from, struct ast_channel *to)
{
- format_t src, dst;
+ struct ast_format_cap *src_cap = from->nativeformats; /* shallow copy, do not destroy */
+ struct ast_format_cap *dst_cap = to->nativeformats; /* shallow copy, do not destroy */
+ struct ast_format best_src_fmt;
+ struct ast_format best_dst_fmt;
int use_slin;
/* See if the channel driver can natively make these two channels compatible */
@@ -5619,20 +5755,17 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
return 0;
}
- if (from->readformat == to->writeformat && from->writeformat == to->readformat) {
+ if ((ast_format_cmp(&from->readformat, &to->writeformat) != AST_FORMAT_CMP_NOT_EQUAL) &&
+ (ast_format_cmp(&to->readformat, &from->writeformat) != AST_FORMAT_CMP_NOT_EQUAL)) {
/* Already compatible! Moving on ... */
return 0;
}
- /* Set up translation from the 'from' channel to the 'to' channel */
- src = from->nativeformats;
- dst = to->nativeformats;
-
/* If there's no audio in this call, don't bother with trying to find a translation path */
- if ((src & AST_FORMAT_AUDIO_MASK) == 0 || (dst & AST_FORMAT_AUDIO_MASK) == 0)
+ if (!ast_format_cap_has_type(src_cap, AST_FORMAT_TYPE_AUDIO) || !ast_format_cap_has_type(dst_cap, AST_FORMAT_TYPE_AUDIO))
return 0;
- if (ast_translator_best_choice(&dst, &src) < 0) {
+ if (ast_translator_best_choice(dst_cap, src_cap, &best_src_fmt, &best_dst_fmt) < 0) {
ast_log(LOG_WARNING, "No path to translate from %s to %s\n", from->name, to->name);
return -1;
}
@@ -5643,16 +5776,20 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
* no direct conversion available. If generic PLC is
* desired, then transcoding via SLINEAR is a requirement
*/
- use_slin = (src == AST_FORMAT_SLINEAR || dst == AST_FORMAT_SLINEAR);
- if ((src != dst) && (ast_opt_generic_plc || ast_opt_transcode_via_slin) &&
- (ast_translate_path_steps(dst, src) != 1 || use_slin))
- dst = AST_FORMAT_SLINEAR;
- if (ast_set_read_format(from, dst) < 0) {
- ast_log(LOG_WARNING, "Unable to set read format on channel %s to %s\n", from->name, ast_getformatname(dst));
+ use_slin = (best_src_fmt.id == AST_FORMAT_SLINEAR || best_dst_fmt.id == AST_FORMAT_SLINEAR);
+ if ((ast_format_cmp(&best_src_fmt, &best_dst_fmt) == AST_FORMAT_CMP_NOT_EQUAL) &&
+ (ast_opt_generic_plc || ast_opt_transcode_via_slin) &&
+ (ast_translate_path_steps(&best_dst_fmt, &best_src_fmt) != 1 || use_slin)) {
+
+ ast_format_set(&best_dst_fmt, AST_FORMAT_SLINEAR, 0);
+ }
+
+ if (ast_set_read_format(from, &best_dst_fmt) < 0) {
+ ast_log(LOG_WARNING, "Unable to set read format on channel %s to %s\n", from->name, ast_getformatname(&best_dst_fmt));
return -1;
}
- if (ast_set_write_format(to, dst) < 0) {
- ast_log(LOG_WARNING, "Unable to set write format on channel %s to %s\n", to->name, ast_getformatname(dst));
+ if (ast_set_write_format(to, &best_dst_fmt) < 0) {
+ ast_log(LOG_WARNING, "Unable to set write format on channel %s to %s\n", to->name, ast_getformatname(&best_dst_fmt));
return -1;
}
return 0;
@@ -6199,8 +6336,7 @@ static void masquerade_colp_transfer(struct ast_channel *transferee, struct xfer
*/
int ast_do_masquerade(struct ast_channel *original)
{
- format_t x;
- int i;
+ int x, i;
int res=0;
int origstate;
int visible_indication;
@@ -6218,13 +6354,17 @@ int ast_do_masquerade(struct ast_channel *original)
struct ast_cdr *cdr;
struct ast_datastore *xfer_ds;
struct xfer_masquerade_ds *xfer_colp;
- format_t rformat = original->readformat;
- format_t wformat = original->writeformat;
+ struct ast_format rformat;
+ struct ast_format wformat;
+ struct ast_format tmp_format;
char newn[AST_CHANNEL_NAME];
char orig[AST_CHANNEL_NAME];
char masqn[AST_CHANNEL_NAME];
char zombn[AST_CHANNEL_NAME];
+ ast_format_copy(&rformat, &original->readformat);
+ ast_format_copy(&wformat, &original->writeformat);
+
/* XXX This operation is a bit odd. We're essentially putting the guts of
* the clone channel into the original channel. Start by killing off the
* original channel's backend. While the features are nice, which is the
@@ -6383,12 +6523,13 @@ int ast_do_masquerade(struct ast_channel *original)
}
/* Swap the raw formats */
- x = original->rawreadformat;
- original->rawreadformat = clonechan->rawreadformat;
- clonechan->rawreadformat = x;
- x = original->rawwriteformat;
- original->rawwriteformat = clonechan->rawwriteformat;
- clonechan->rawwriteformat = x;
+ ast_format_copy(&tmp_format, &original->rawreadformat);
+ ast_format_copy(&original->rawreadformat, &clonechan->rawreadformat);
+ ast_format_copy(&clonechan->rawreadformat, &tmp_format);
+
+ ast_format_copy(&tmp_format, &original->rawwriteformat);
+ ast_format_copy(&original->rawwriteformat, &clonechan->rawwriteformat);
+ ast_format_copy(&clonechan->rawwriteformat, &tmp_format);
clonechan->_softhangup = AST_SOFTHANGUP_DEV;
@@ -6486,16 +6627,16 @@ int ast_do_masquerade(struct ast_channel *original)
ast_channel_set_fd(original, AST_TIMING_FD, original->timingfd);
/* Our native formats are different now */
- original->nativeformats = clonechan->nativeformats;
+ ast_format_cap_copy(original->nativeformats, clonechan->nativeformats);
/* Context, extension, priority, app data, jump table, remain the same */
/* pvt switches. pbx stays the same, as does next */
/* Set the write format */
- ast_set_write_format(original, wformat);
+ ast_set_write_format(original, &wformat);
/* Set the read format */
- ast_set_read_format(original, rformat);
+ ast_set_read_format(original, &rformat);
/* Copy the music class */
ast_string_field_set(original, musicclass, clonechan->musicclass);
@@ -6509,7 +6650,7 @@ int ast_do_masquerade(struct ast_channel *original)
}
ast_debug(1, "Putting channel %s in %s/%s formats\n", original->name,
- ast_getformatname(wformat), ast_getformatname(rformat));
+ ast_getformatname(&wformat), ast_getformatname(&rformat));
/* Okay. Last thing is to let the channel driver know about all this mess, so he
can fix up everything as best as possible */
@@ -6753,8 +6894,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
struct ast_channel *cs[3];
struct ast_frame *f;
enum ast_bridge_result res = AST_BRIDGE_COMPLETE;
- format_t o0nativeformats;
- format_t o1nativeformats;
+ struct ast_format_cap *o0nativeformats;
+ struct ast_format_cap *o1nativeformats;
int watch_c0_dtmf;
int watch_c1_dtmf;
void *pvt0, *pvt1;
@@ -6762,13 +6903,20 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
int frame_put_in_jb = 0;
int jb_in_use;
int to;
-
+
+ o0nativeformats = ast_format_cap_dup(c0->nativeformats);
+ o1nativeformats = ast_format_cap_dup(c1->nativeformats);
+
+ if (!o0nativeformats || !o1nativeformats) {
+ ast_format_cap_destroy(o0nativeformats); /* NULL safe */
+ ast_format_cap_destroy(o1nativeformats); /* NULL safe */
+ return AST_BRIDGE_FAILED;
+ }
+
cs[0] = c0;
cs[1] = c1;
pvt0 = c0->tech_pvt;
pvt1 = c1->tech_pvt;
- o0nativeformats = c0->nativeformats;
- o1nativeformats = c1->nativeformats;
watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0;
watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1;
@@ -6790,8 +6938,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
struct ast_channel *who, *other;
if ((c0->tech_pvt != pvt0) || (c1->tech_pvt != pvt1) ||
- (o0nativeformats != c0->nativeformats) ||
- (o1nativeformats != c1->nativeformats)) {
+ (!ast_format_cap_identical(o0nativeformats, c0->nativeformats)) ||
+ (!ast_format_cap_identical(o1nativeformats, c1->nativeformats))) {
/* Check for Masquerade, codec changes, etc */
res = AST_BRIDGE_RETRY;
break;
@@ -6941,6 +7089,9 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
ast_poll_channel_del(c0, c1);
+ ast_format_cap_destroy(o0nativeformats);
+ ast_format_cap_destroy(o1nativeformats);
+
return res;
}
@@ -7050,8 +7201,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
{
struct ast_channel *chans[2] = { c0, c1 };
enum ast_bridge_result res = AST_BRIDGE_COMPLETE;
- format_t o0nativeformats;
- format_t o1nativeformats;
+ struct ast_format_cap *o0nativeformats;
+ struct ast_format_cap *o1nativeformats;
long time_left_ms=0;
char caller_warning = 0;
char callee_warning = 0;
@@ -7072,6 +7223,16 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
ast_test_flag(c1, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1))
return -1;
+ o0nativeformats = ast_format_cap_dup(c0->nativeformats);
+ o1nativeformats = ast_format_cap_dup(c1->nativeformats);
+ if (!o0nativeformats || !o1nativeformats) {
+ ast_format_cap_destroy(o0nativeformats);
+ ast_format_cap_destroy(o1nativeformats);
+ ast_log(LOG_WARNING, "failed to copy native formats\n");
+ return -1;
+ }
+
+
*fo = NULL;
if (ast_tvzero(config->start_time)) {
@@ -7092,9 +7253,6 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
ast_set_owners_and_peers(c0, c1);
- o0nativeformats = c0->nativeformats;
- o1nativeformats = c1->nativeformats;
-
if (config->feature_timer && !ast_tvzero(config->nexteventts)) {
config->nexteventts = ast_tvadd(config->feature_start_time, ast_samp2tv(config->feature_timer, 1000));
} else if (config->timelimit) {
@@ -7245,6 +7403,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
c0->_bridge = NULL;
c1->_bridge = NULL;
+ ast_format_cap_destroy(o0nativeformats);
+ ast_format_cap_destroy(o1nativeformats);
return res;
} else {
ast_clear_flag(c0, AST_FLAG_NBRIDGE);
@@ -7264,16 +7424,21 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
}
}
- if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat) ||
- (c0->nativeformats != o0nativeformats) || (c1->nativeformats != o1nativeformats)) &&
+ if (((ast_format_cmp(&c1->readformat, &c0->writeformat) == AST_FORMAT_CMP_NOT_EQUAL) ||
+ (ast_format_cmp(&c0->readformat, &c1->writeformat) == AST_FORMAT_CMP_NOT_EQUAL) ||
+ !ast_format_cap_identical(c0->nativeformats, o0nativeformats) ||
+ !ast_format_cap_identical(c1->nativeformats, o1nativeformats)) &&
!(c0->generator || c1->generator)) {
if (ast_channel_make_compatible(c0, c1)) {
ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
manager_bridge_event(0, 1, c0, c1);
+ ast_format_cap_destroy(o0nativeformats);
+ ast_format_cap_destroy(o1nativeformats);
return AST_BRIDGE_FAILED;
}
- o0nativeformats = c0->nativeformats;
- o1nativeformats = c1->nativeformats;
+
+ ast_format_cap_copy(o0nativeformats, c0->nativeformats);
+ ast_format_cap_copy(o1nativeformats, c1->nativeformats);
}
update_bridge_vars(c0, c1);
@@ -7310,6 +7475,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
S_COR(c1->caller.id.number.valid, c1->caller.id.number.str, "<unknown>"));
ast_debug(1, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name);
+ ast_format_cap_destroy(o0nativeformats);
+ ast_format_cap_destroy(o1nativeformats);
return res;
}
@@ -7356,7 +7523,7 @@ struct tonepair_state {
int v1_2;
int v2_2;
int v3_2;
- format_t origwfmt;
+ struct ast_format origwfmt;
int pos;
int duration;
int modulate;
@@ -7370,7 +7537,7 @@ static void tonepair_release(struct ast_channel *chan, void *params)
struct tonepair_state *ts = params;
if (chan)
- ast_set_write_format(chan, ts->origwfmt);
+ ast_set_write_format(chan, &ts->origwfmt);
ast_free(ts);
}
@@ -7381,8 +7548,8 @@ static void *tonepair_alloc(struct ast_channel *chan, void *params)
if (!(ts = ast_calloc(1, sizeof(*ts))))
return NULL;
- ts->origwfmt = chan->writeformat;
- if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
+ ast_format_copy(&ts->origwfmt, &chan->writeformat);
+ if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
tonepair_release(NULL, ts);
ts = NULL;
@@ -7436,7 +7603,7 @@ static int tonepair_generator(struct ast_channel *chan, void *data, int len, int
ts->data[x] = ts->v3_1 + ts->v3_2;
}
ts->f.frametype = AST_FRAME_VOICE;
- ts->f.subclass.codec = AST_FORMAT_SLINEAR;
+ ast_format_set(&ts->f.subclass.format, AST_FORMAT_SLINEAR, 0);
ts->f.datalen = len;
ts->f.samples = samples;
ts->f.offset = AST_FRIENDLY_OFFSET;
@@ -7778,11 +7945,11 @@ static int silence_generator_generate(struct ast_channel *chan, void *data, int
short buf[samples];
struct ast_frame frame = {
.frametype = AST_FRAME_VOICE,
- .subclass.codec = AST_FORMAT_SLINEAR,
.data.ptr = buf,
.samples = samples,
.datalen = sizeof(buf),
};
+ ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0);
memset(buf, 0, sizeof(buf));
@@ -7799,7 +7966,7 @@ static struct ast_generator silence_generator = {
};
struct ast_silence_generator {
- int old_write_format;
+ struct ast_format old_write_format;
};
struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan)
@@ -7810,9 +7977,9 @@ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_cha
return NULL;
}
- state->old_write_format = chan->writeformat;
+ ast_format_copy(&state->old_write_format, &chan->writeformat);
- if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
+ if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_ERROR, "Could not set write format to SLINEAR\n");
ast_free(state);
return NULL;
@@ -7834,7 +8001,7 @@ void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_sil
ast_debug(1, "Stopped silence generator on '%s'\n", chan->name);
- if (ast_set_write_format(chan, state->old_write_format) < 0)
+ if (ast_set_write_format(chan, &state->old_write_format) < 0)
ast_log(LOG_ERROR, "Could not return write format to its original state\n");
ast_free(state);
diff --git a/main/cli.c b/main/cli.c
index 7f4c1791f..671a2bac7 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -1387,7 +1387,7 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
struct timeval now;
struct ast_str *out = ast_str_thread_get(&ast_str_thread_global_buf, 16);
char cdrtime[256];
- char nf[256], wf[256], rf[256];
+ char nf[256];
struct ast_str *write_transpath = ast_str_alloca(256);
struct ast_str *read_transpath = ast_str_alloca(256);
long elapsed_seconds=0;
@@ -1469,9 +1469,9 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
S_OR(c->dialed.number.str, "(N/A)"),
c->language,
ast_state2str(c->_state), c->_state, c->rings,
- ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
- ast_getformatname_multiple(wf, sizeof(wf), c->writeformat),
- ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
+ ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
+ ast_getformatname(&c->writeformat),
+ ast_getformatname(&c->readformat),
c->writetrans ? "Yes" : "No",
ast_translate_path_to_str(c->writetrans, &write_transpath),
c->readtrans ? "Yes" : "No",
diff --git a/main/data.c b/main/data.c
index 3b2c124ab..3ca2f7c27 100644
--- a/main/data.c
+++ b/main/data.c
@@ -3100,7 +3100,7 @@ static int manager_data_get(struct mansession *s, const struct message *m)
return RESULT_SUCCESS;
}
-int ast_data_add_codecs(struct ast_data *root, const char *node_name, format_t capability)
+int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_format *format)
{
struct ast_data *codecs, *codec;
size_t fmlist_size;
@@ -3113,7 +3113,36 @@ int ast_data_add_codecs(struct ast_data *root, const char *node_name, format_t c
}
fmlist = ast_get_format_list(&fmlist_size);
for (x = 0; x < fmlist_size; x++) {
- if (fmlist[x].bits & capability) {
+ if (fmlist[x].id == format->id) {
+ codec = ast_data_add_node(codecs, "codec");
+ if (!codec) {
+ return -1;
+ }
+ ast_data_add_str(codec, "name", fmlist[x].name);
+ ast_data_add_int(codec, "samplespersecond", fmlist[x].samplespersecond);
+ ast_data_add_str(codec, "description", fmlist[x].desc);
+ ast_data_add_int(codec, "frame_length", fmlist[x].fr_len);
+ }
+ }
+
+ return 0;
+}
+
+int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast_format_cap *cap)
+{
+ struct ast_data *codecs, *codec;
+ size_t fmlist_size;
+ const struct ast_format_list *fmlist;
+ struct ast_format tmp_fmt;
+ int x;
+
+ codecs = ast_data_add_node(root, node_name);
+ if (!codecs) {
+ return -1;
+ }
+ fmlist = ast_get_format_list(&fmlist_size);
+ for (x = 0; x < fmlist_size; x++) {
+ if (ast_format_cap_iscompatible(cap, ast_format_set(&tmp_fmt, fmlist[x].id, 0))) {
codec = ast_data_add_node(codecs, "codec");
if (!codec) {
return -1;
diff --git a/main/dial.c b/main/dial.c
index ba1a2bb53..5c30e287d 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -248,13 +248,27 @@ static int begin_dial_channel(struct ast_dial_channel *channel, struct ast_chann
{
char numsubst[AST_MAX_EXTENSION];
int res = 1;
+ struct ast_format_cap *cap_all_audio = NULL;
+ struct ast_format_cap *cap_request;
/* Copy device string over */
ast_copy_string(numsubst, channel->device, sizeof(numsubst));
+ if (chan) {
+ cap_request = chan->nativeformats;
+ } else {
+ cap_all_audio = ast_format_cap_alloc_nolock();
+ ast_format_cap_add_all_by_type(cap_all_audio, AST_FORMAT_TYPE_AUDIO);
+ cap_request = cap_all_audio;
+ }
+
/* If we fail to create our owner channel bail out */
- if (!(channel->owner = ast_request(channel->tech, chan ? chan->nativeformats : AST_FORMAT_AUDIO_MASK, chan, numsubst, &channel->cause)))
+ if (!(channel->owner = ast_request(channel->tech, cap_request, chan, numsubst, &channel->cause))) {
+ cap_all_audio = ast_format_cap_destroy(cap_all_audio);
return -1;
+ }
+ cap_request = NULL;
+ cap_all_audio = ast_format_cap_destroy(cap_all_audio);
channel->owner->appl = "AppDial2";
channel->owner->data = "(Outgoing Line)";
diff --git a/main/dsp.c b/main/dsp.c
index cba01b5f1..69989afe8 100644
--- a/main/dsp.c
+++ b/main/dsp.c
@@ -1106,7 +1106,7 @@ int ast_dsp_call_progress(struct ast_dsp *dsp, struct ast_frame *inf)
ast_log(LOG_WARNING, "Can't check call progress of non-voice frames\n");
return 0;
}
- if (inf->subclass.codec != AST_FORMAT_SLINEAR) {
+ if (inf->subclass.format.id != AST_FORMAT_SLINEAR) {
ast_log(LOG_WARNING, "Can only check call progress in signed-linear frames\n");
return 0;
}
@@ -1280,7 +1280,7 @@ int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
ast_log(LOG_WARNING, "Can't calculate silence on a non-voice frame\n");
return 0;
}
- if (f->subclass.codec != AST_FORMAT_SLINEAR) {
+ if (f->subclass.format.id != AST_FORMAT_SLINEAR) {
ast_log(LOG_WARNING, "Can only calculate silence on signed-linear frames :(\n");
return 0;
}
@@ -1298,7 +1298,7 @@ int ast_dsp_noise(struct ast_dsp *dsp, struct ast_frame *f, int *totalnoise)
ast_log(LOG_WARNING, "Can't calculate noise on a non-voice frame\n");
return 0;
}
- if (f->subclass.codec != AST_FORMAT_SLINEAR) {
+ if (f->subclass.format.id != AST_FORMAT_SLINEAR) {
ast_log(LOG_WARNING, "Can only calculate noise on signed-linear frames :(\n");
return 0;
}
@@ -1329,7 +1329,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
odata = af->data.ptr;
len = af->datalen;
/* Make sure we have short data */
- switch (af->subclass.codec) {
+ switch (af->subclass.format.id) {
case AST_FORMAT_SLINEAR:
shortdata = af->data.ptr;
len = af->datalen / 2;
@@ -1350,7 +1350,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
default:
/*Display warning only once. Otherwise you would get hundreds of warnings every second */
if (dsp->display_inband_dtmf_warning)
- ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(af->subclass.codec));
+ ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&af->subclass.format));
dsp->display_inband_dtmf_warning = 0;
return af;
}
@@ -1479,7 +1479,7 @@ done:
memset(shortdata + dsp->mute_data[x].start, 0, sizeof(int16_t) * (dsp->mute_data[x].end - dsp->mute_data[x].start));
}
- switch (af->subclass.codec) {
+ switch (af->subclass.format.id) {
case AST_FORMAT_SLINEAR:
break;
case AST_FORMAT_ULAW:
@@ -1491,6 +1491,8 @@ done:
for (x = 0; x < len; x++) {
odata[x] = AST_LIN2A((unsigned short) shortdata[x]);
}
+ /* fall through */
+ default:
break;
}
diff --git a/main/features.c b/main/features.c
index 413f8170a..f35a2475a 100644
--- a/main/features.c
+++ b/main/features.c
@@ -743,7 +743,7 @@ static void check_goto_on_transfer(struct ast_channel *chan)
static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
const char *caller_name, struct ast_channel *requestor,
- struct ast_channel *transferee, const char *type, format_t format, void *data,
+ struct ast_channel *transferee, const char *type, struct ast_format_cap *cap, void *data,
int timeout, int *outstate, const char *language);
/*!
@@ -1315,17 +1315,20 @@ static int fake_fixup(struct ast_channel *clonechan, struct ast_channel *origina
static struct ast_channel *create_test_channel(const struct ast_channel_tech *fake_tech)
{
struct ast_channel *test_channel1;
+ struct ast_format tmp_fmt;
if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
NULL, NULL, 0, 0, "TestChannel1"))) {
return NULL;
}
/* normally this is done in the channel driver */
- test_channel1->nativeformats = AST_FORMAT_GSM;
- test_channel1->writeformat = AST_FORMAT_GSM;
- test_channel1->rawwriteformat = AST_FORMAT_GSM;
- test_channel1->readformat = AST_FORMAT_GSM;
- test_channel1->rawreadformat = AST_FORMAT_GSM;
+ ast_format_cap_add(test_channel1->nativeformats, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0));
+
+ ast_format_set(&test_channel1->writeformat, AST_FORMAT_GSM, 0);
+ ast_format_set(&test_channel1->rawwriteformat, AST_FORMAT_GSM, 0);
+ ast_format_set(&test_channel1->readformat, AST_FORMAT_GSM, 0);
+ ast_format_set(&test_channel1->rawreadformat, AST_FORMAT_GSM, 0);
+
test_channel1->tech = fake_tech;
return test_channel1;
@@ -2136,7 +2139,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
/* Dial party C */
newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer,
- transferee, "Local", ast_best_codec(transferer->nativeformats), xferto,
+ transferee, "Local", transferer->nativeformats, xferto,
atxfernoanswertimeout, &outstate, transferer->language);
ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
@@ -2243,14 +2246,13 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
transferer_tech, transferer_name);
newchan = feature_request_and_dial(transferer, transferer_name_orig,
transferee, transferee, transferer_tech,
- ast_best_codec(transferee->nativeformats), transferer_name,
+ transferee->nativeformats, transferer_name,
atxfernoanswertimeout, &outstate, transferer->language);
ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
!!newchan, outstate);
if (newchan || ast_check_hangup(transferee)) {
break;
}
-
++tries;
if (atxfercallbackretries <= tries) {
/* No more callback tries remaining. */
@@ -2272,7 +2274,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto);
newchan = feature_request_and_dial(transferer, transferer_name_orig,
transferer, transferee, "Local",
- ast_best_codec(transferee->nativeformats), xferto,
+ transferee->nativeformats, xferto,
atxfernoanswertimeout, &outstate, transferer->language);
ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n",
!!newchan, outstate);
@@ -2980,7 +2982,7 @@ static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer,
*/
static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
const char *caller_name, struct ast_channel *requestor,
- struct ast_channel *transferee, const char *type, format_t format, void *data,
+ struct ast_channel *transferee, const char *type, struct ast_format_cap *cap, void *data,
int timeout, int *outstate, const char *language)
{
int state = 0;
@@ -2996,12 +2998,21 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
struct timeval started;
int x, len = 0;
char *disconnect_code = NULL, *dialed_code = NULL;
+ struct ast_format_cap *tmp_cap;
+ struct ast_format best_audio_fmt;
struct ast_frame *f;
AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
+ tmp_cap = ast_format_cap_alloc_nolock();
+ if (!tmp_cap) {
+ return NULL;
+ }
+ ast_best_codec(cap, &best_audio_fmt);
+ ast_format_cap_add(tmp_cap, &best_audio_fmt);
+
caller_hungup = ast_check_hangup(caller);
- if (!(chan = ast_request(type, format, requestor, data, &cause))) {
+ if (!(chan = ast_request(type, tmp_cap, requestor, data, &cause))) {
ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
switch (cause) {
case AST_CAUSE_BUSY:
@@ -3119,8 +3130,7 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
}
} else if (chan == active_channel) {
if (!ast_strlen_zero(chan->call_forward)) {
- state = 0;
- chan = ast_call_forward(caller, chan, NULL, format, NULL, &state);
+ chan = ast_call_forward(caller, chan, NULL, tmp_cap, NULL, &state);
if (!chan) {
break;
}
@@ -3252,6 +3262,8 @@ done:
chan = NULL;
}
+ tmp_cap = ast_format_cap_destroy(tmp_cap);
+
if (outstate)
*outstate = state;
diff --git a/main/file.c b/main/file.c
index c2ab096cd..57bf1570c 100644
--- a/main/file.c
+++ b/main/file.c
@@ -59,11 +59,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
*/
int ast_language_is_prefix = 1;
-static AST_RWLIST_HEAD_STATIC(formats, ast_format);
+static AST_RWLIST_HEAD_STATIC(formats, ast_format_def);
-int __ast_format_register(const struct ast_format *f, struct ast_module *mod)
+int __ast_format_def_register(const struct ast_format_def *f, struct ast_module *mod)
{
- struct ast_format *tmp;
+ struct ast_format_def *tmp;
AST_RWLIST_WRLOCK(&formats);
AST_RWLIST_TRAVERSE(&formats, tmp, list) {
@@ -98,9 +98,9 @@ int __ast_format_register(const struct ast_format *f, struct ast_module *mod)
return 0;
}
-int ast_format_unregister(const char *name)
+int ast_format_def_unregister(const char *name)
{
- struct ast_format *tmp;
+ struct ast_format_def *tmp;
int res = -1;
AST_RWLIST_WRLOCK(&formats);
@@ -130,8 +130,8 @@ int ast_stopstream(struct ast_channel *tmp)
if (tmp->stream) {
ast_closestream(tmp->stream);
tmp->stream = NULL;
- if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
- ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_getformatname(tmp->oldwriteformat));
+ if (tmp->oldwriteformat.id && ast_set_write_format(tmp, &tmp->oldwriteformat))
+ ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_getformatname(&tmp->oldwriteformat));
}
/* Stop the video stream too */
if (tmp->vstream != NULL) {
@@ -149,10 +149,10 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
int res = -1;
int alt = 0;
if (f->frametype == AST_FRAME_VIDEO) {
- if (fs->fmt->format & AST_FORMAT_AUDIO_MASK) {
+ if (AST_FORMAT_GET_TYPE(fs->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) {
/* This is the audio portion. Call the video one... */
if (!fs->vfs && fs->filename) {
- const char *type = ast_getformatname(f->subclass.codec & ~0x1);
+ const char *type = ast_getformatname(&f->subclass.format);
fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
ast_debug(1, "Opened video output file\n");
}
@@ -168,7 +168,7 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
return -1;
}
- if (((fs->fmt->format | alt) & f->subclass.codec) == f->subclass.codec) {
+ if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) != AST_FORMAT_CMP_NOT_EQUAL) {
res = fs->fmt->write(fs, f);
if (res < 0)
ast_log(LOG_WARNING, "Natural write failed\n");
@@ -177,18 +177,18 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
} else {
/* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
the one we've setup a translator for, we do the "wrong thing" XXX */
- if (fs->trans && f->subclass.codec != fs->lastwriteformat) {
+ if (fs->trans && (ast_format_cmp(&f->subclass.format, &fs->lastwriteformat) != AST_FORMAT_CMP_EQUAL)) {
ast_translator_free_path(fs->trans);
fs->trans = NULL;
}
if (!fs->trans)
- fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass.codec);
+ fs->trans = ast_translator_build_path(&fs->fmt->format, &f->subclass.format);
if (!fs->trans)
ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n",
- fs->fmt->name, ast_getformatname(f->subclass.codec));
+ fs->fmt->name, ast_getformatname(&f->subclass.format));
else {
struct ast_frame *trf;
- fs->lastwriteformat = f->subclass.codec;
+ ast_format_copy(&fs->lastwriteformat, &f->subclass.format);
/* Get the translated frame but don't consume the original in case they're using it on another stream */
if ((trf = ast_translate(fs->trans, f, 0))) {
struct ast_frame *cur;
@@ -296,7 +296,7 @@ static void filestream_destructor(void *arg)
/* Stop a running stream if there is one */
if (f->owner) {
- if (f->fmt->format < AST_FORMAT_AUDIO_MASK) {
+ if (AST_FORMAT_GET_TYPE(f->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) {
f->owner->stream = NULL;
AST_SCHED_DEL(f->owner->sched, f->owner->streamid);
ast_settimeout(f->owner, 0, NULL, NULL);
@@ -335,7 +335,7 @@ static void filestream_destructor(void *arg)
ast_module_unref(f->fmt->module);
}
-static struct ast_filestream *get_filestream(struct ast_format *fmt, FILE *bfile)
+static struct ast_filestream *get_filestream(struct ast_format_def *fmt, FILE *bfile)
{
struct ast_filestream *s;
@@ -361,7 +361,7 @@ enum wrap_fn { WRAP_OPEN, WRAP_REWRITE };
static int fn_wrapper(struct ast_filestream *s, const char *comment, enum wrap_fn mode)
{
- struct ast_format *f = s->fmt;
+ struct ast_format_def *f = s->fmt;
int ret = -1;
int (*openfn)(struct ast_filestream *s);
@@ -396,18 +396,20 @@ enum file_action {
};
/*!
+ * \internal
* \brief perform various actions on a file. Second argument
- * arg2 depends on the command:
- * unused for EXISTS and DELETE
+ * \note arg2 depends on the command:
+ * unused for DELETE
+ * optional ast_format_cap holding all the formats found for a file, for EXISTS.
* destination file name (const char *) for COPY and RENAME
* struct ast_channel * for OPEN
* if fmt is NULL, OPEN will return the first matching entry,
* whereas other functions will run on all matching entries.
*/
-static format_t ast_filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
+static int filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
{
- struct ast_format *f;
- format_t res = (action == ACTION_EXISTS) ? 0 : -1;
+ struct ast_format_def *f;
+ int res = (action == ACTION_EXISTS) ? 0 : -1;
AST_RWLIST_RDLOCK(&formats);
/* Check for a specific format */
@@ -441,9 +443,9 @@ static format_t ast_filehelper(const char *filename, const void *arg2, const cha
FILE *bfile;
struct ast_filestream *s;
- if ( !(chan->writeformat & f->format) &&
- !((f->format & AST_FORMAT_AUDIO_MASK && fmt) ||
- (f->format & AST_FORMAT_VIDEO_MASK && fmt))) {
+ if ((ast_format_cmp(&chan->writeformat, &f->format) == AST_FORMAT_CMP_NOT_EQUAL) &&
+ !(((AST_FORMAT_GET_TYPE(f->format.id) == AST_FORMAT_TYPE_AUDIO) && fmt) ||
+ ((AST_FORMAT_GET_TYPE(f->format.id) == AST_FORMAT_TYPE_VIDEO) && fmt))) {
ast_free(fn);
continue; /* not a supported format */
}
@@ -471,7 +473,7 @@ static format_t ast_filehelper(const char *filename, const void *arg2, const cha
s->fmt = f;
s->trans = NULL;
s->filename = NULL;
- if (s->fmt->format & AST_FORMAT_AUDIO_MASK) {
+ if (AST_FORMAT_GET_TYPE(s->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) {
if (chan->stream)
ast_closestream(chan->stream);
chan->stream = s;
@@ -488,7 +490,12 @@ static format_t ast_filehelper(const char *filename, const void *arg2, const cha
break; /* will never get here */
case ACTION_EXISTS: /* return the matching format */
- res |= f->format;
+ /* if arg2 is present, it is a format capabilities structure.
+ * Add this format to the set of formats this file can be played in */
+ if (arg2) {
+ ast_format_cap_add((struct ast_format_cap *) arg2, &f->format);
+ }
+ res = 1; /* file does exist and format it exists in is returned in arg2 */
break;
case ACTION_DELETE:
@@ -527,11 +534,17 @@ static int is_absolute_path(const char *filename)
return filename[0] == '/';
}
-static format_t fileexists_test(const char *filename, const char *fmt, const char *lang,
- char *buf, int buflen)
+/*!
+ * \brief test if a file exists for a given format.
+ * \note result_cap is OPTIONAL
+ * \retval 1, true and result_cap represents format capabilities file exists in.
+ * \retval 0, false
+ */
+static int fileexists_test(const char *filename, const char *fmt, const char *lang,
+ char *buf, int buflen, struct ast_format_cap *result_cap)
{
if (buf == NULL) {
- return -1;
+ return 0;
}
if (ast_language_is_prefix && !is_absolute_path(filename)) { /* new layout */
@@ -550,25 +563,36 @@ static format_t fileexists_test(const char *filename, const char *fmt, const cha
}
}
- return ast_filehelper(buf, NULL, fmt, ACTION_EXISTS);
+ return filehelper(buf, result_cap, fmt, ACTION_EXISTS);
}
/*!
* \brief helper routine to locate a file with a given format
* and language preference.
- * Try preflang, preflang with stripped '_' suffices, or NULL.
+ *
+ * \note Try preflang, preflang with stripped '_' suffices, or NULL.
*
- * The last parameter(s) point to a buffer of sufficient size,
+ * \note The last parameter(s) point to a buffer of sufficient size,
* which on success is filled with the matching filename.
+ *
+ * \param filename, name of the file.
+ * \param fmt, format to look for the file in. OPTIONAL
+ * \param preflang, the perfered language
+ * \param buf, returns the matching filename
+ * \param buflen, size of the buf
+ * \param result_cap, OPTIONAL format capabilities result structure
+ * returns what formats the file was found in.
+ *
+ * \retval 1, true. file exists and result format is set
+ * \retval 0, false. file does not exist.
*/
-static format_t fileexists_core(const char *filename, const char *fmt, const char *preflang,
- char *buf, int buflen)
+static int fileexists_core(const char *filename, const char *fmt, const char *preflang,
+ char *buf, int buflen, struct ast_format_cap *result_cap)
{
- format_t res = -1;
char *lang;
if (buf == NULL) {
- return -1;
+ return 0;
}
/* We try languages in the following order:
@@ -584,8 +608,8 @@ static format_t fileexists_core(const char *filename, const char *fmt, const cha
while (!ast_strlen_zero(lang)) {
char *end;
- if ((res = fileexists_test(filename, fmt, lang, buf, buflen)) > 0) {
- return res;
+ if (fileexists_test(filename, fmt, lang, buf, buflen, result_cap)) {
+ return 1;
}
if ((end = strrchr(lang, '_')) != NULL) {
@@ -597,14 +621,14 @@ static format_t fileexists_core(const char *filename, const char *fmt, const cha
}
/* Try without any language */
- if ((res = fileexists_test(filename, fmt, NULL, buf, buflen)) > 0) {
- return res;
+ if (fileexists_test(filename, fmt, NULL, buf, buflen, result_cap)) {
+ return 1;
}
/* Finally try the default language unless it was already tried before */
if ((ast_strlen_zero(preflang) || strcmp(preflang, DEFAULT_LANGUAGE)) && (ast_strlen_zero(lang) || strcmp(lang, DEFAULT_LANGUAGE))) {
- if ((res = fileexists_test(filename, fmt, DEFAULT_LANGUAGE, buf, buflen)) > 0) {
- return res;
+ if ((fileexists_test(filename, fmt, DEFAULT_LANGUAGE, buf, buflen, result_cap)) > 0) {
+ return 1;
}
}
@@ -623,7 +647,8 @@ struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char
* language and format, set up a suitable translator,
* and open the stream.
*/
- format_t fmts, res;
+ struct ast_format_cap *file_fmt_cap;
+ int res;
int buflen;
char *buf;
@@ -639,20 +664,29 @@ struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char
buf = alloca(buflen);
if (buf == NULL)
return NULL;
- fmts = fileexists_core(filename, NULL, preflang, buf, buflen);
- if (fmts > 0)
- fmts &= AST_FORMAT_AUDIO_MASK;
- if (fmts < 1) {
+
+ if (!(file_fmt_cap = ast_format_cap_alloc_nolock())) {
+ return NULL;
+ }
+ if (!fileexists_core(filename, NULL, preflang, buf, buflen, file_fmt_cap) ||
+ !ast_format_cap_has_type(file_fmt_cap, AST_FORMAT_TYPE_AUDIO)) {
+
ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
+ file_fmt_cap = ast_format_cap_destroy(file_fmt_cap);
return NULL;
}
- chan->oldwriteformat = chan->writeformat;
- /* Set the channel to a format we can work with */
- res = ast_set_write_format(chan, fmts);
+
+ /* Set the channel to a format we can work with and save off the previous format. */
+ ast_format_copy(&chan->oldwriteformat, &chan->writeformat);
+ /* Set the channel to the best format that exists for the file. */
+ res = ast_set_write_format_from_cap(chan, file_fmt_cap);
+ /* don't need this anymore now that the channel's write format is set. */
+ file_fmt_cap = ast_format_cap_destroy(file_fmt_cap);
+
if (res == -1) { /* No format available that works with this channel */
return NULL;
}
- res = ast_filehelper(buf, chan, NULL, ACTION_OPEN);
+ res = filehelper(buf, chan, NULL, ACTION_OPEN);
if (res >= 0)
return chan->stream;
return NULL;
@@ -663,9 +697,12 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil
/* As above, but for video. But here we don't have translators
* so we must enforce a format.
*/
- format_t format;
+ struct ast_format tmp_fmt;
+ struct ast_format_cap *tmp_cap;
char *buf;
int buflen;
+ const char *fmt;
+ int fd;
if (preflang == NULL)
preflang = "";
@@ -674,20 +711,39 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil
if (buf == NULL)
return NULL;
- for (format = AST_FORMAT_AUDIO_MASK + 1; format <= AST_FORMAT_VIDEO_MASK; format = format << 1) {
- int fd;
- const char *fmt;
+ /* is the channel capable of video without translation ?*/
+ if (!ast_format_cap_has_type(chan->nativeformats, AST_FORMAT_TYPE_VIDEO)) {
+ return NULL;
+ }
+ if (!(tmp_cap = ast_format_cap_alloc_nolock())) {
+ return NULL;
+ }
+ /* Video is supported, so see what video formats exist for this file */
+ if (!fileexists_core(filename, NULL, preflang, buf, buflen, tmp_cap)) {
+ tmp_cap = ast_format_cap_destroy(tmp_cap);
+ return NULL;
+ }
- if (!(chan->nativeformats & format))
+ /* iterate over file formats and pick the first one compatible with the channel's native formats */
+ ast_format_cap_iter_start(tmp_cap);
+ while (!ast_format_cap_iter_next(tmp_cap, &tmp_fmt)) {
+ fmt = ast_getformatname(&tmp_fmt);
+ if ((AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) ||
+ !ast_format_cap_iscompatible(chan->nativeformats, &tmp_fmt)) {
continue;
- fmt = ast_getformatname(format);
- if ( fileexists_core(filename, fmt, preflang, buf, buflen) < 1) /* no valid format */
- continue;
- fd = ast_filehelper(buf, chan, fmt, ACTION_OPEN);
- if (fd >= 0)
+ }
+
+ fd = filehelper(buf, chan, fmt, ACTION_OPEN);
+ if (fd >= 0) {
+ ast_format_cap_iter_end(tmp_cap);
+ tmp_cap = ast_format_cap_destroy(tmp_cap);
return chan->vstream;
+ }
ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
}
+ ast_format_cap_iter_end(tmp_cap);
+ tmp_cap = ast_format_cap_destroy(tmp_cap);
+
return NULL;
}
@@ -759,7 +815,7 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
if (whennext != s->lasttimeout) {
if (s->owner->timingfd > -1) {
- float samp_rate = (float) ast_format_rate(s->fmt->format);
+ float samp_rate = (float) ast_format_rate(&s->fmt->format);
unsigned int rate;
rate = (unsigned int) roundf(samp_rate / ((float) whennext));
@@ -767,7 +823,7 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
ast_settimeout(s->owner, rate, ast_fsread_audio, s);
} else {
s->owner->streamid = ast_sched_add(s->owner->sched,
- whennext / (ast_format_rate(s->fmt->format) / 1000), ast_fsread_audio, s);
+ whennext / (ast_format_rate(&s->fmt->format) / 1000), ast_fsread_audio, s);
}
s->lasttimeout = whennext;
return FSREAD_SUCCESS_NOSCHED;
@@ -818,7 +874,7 @@ static enum fsread_res ast_readvideo_callback(struct ast_filestream *s)
if (whennext != s->lasttimeout) {
s->owner->vstreamid = ast_sched_add(s->owner->sched,
- whennext / (ast_format_rate(s->fmt->format) / 1000),
+ whennext / (ast_format_rate(&s->fmt->format) / 1000),
ast_fsread_video, s);
s->lasttimeout = whennext;
return FSREAD_SUCCESS_NOSCHED;
@@ -850,7 +906,7 @@ int ast_playstream(struct ast_filestream *s)
{
enum fsread_res res;
- if (s->fmt->format & AST_FORMAT_AUDIO_MASK)
+ if (AST_FORMAT_GET_TYPE(s->fmt->format.id) == AST_FORMAT_TYPE_AUDIO)
res = ast_readaudio_callback(s);
else
res = ast_readvideo_callback(s);
@@ -892,7 +948,7 @@ int ast_closestream(struct ast_filestream *f)
/* Stop a running stream if there is one */
if (f->owner) {
- if (f->fmt->format < AST_FORMAT_AUDIO_MASK) {
+ if (AST_FORMAT_GET_TYPE(f->fmt->format.id) == AST_FORMAT_TYPE_AUDIO) {
f->owner->stream = NULL;
AST_SCHED_DEL(f->owner->sched, f->owner->streamid);
ast_settimeout(f->owner, 0, NULL, NULL);
@@ -921,22 +977,22 @@ int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
buf = alloca(buflen);
if (buf == NULL)
return 0;
- return fileexists_core(filename, fmt, preflang, buf, buflen);
+ return fileexists_core(filename, fmt, preflang, buf, buflen, NULL) ? 1 : 0;
}
int ast_filedelete(const char *filename, const char *fmt)
{
- return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
+ return filehelper(filename, NULL, fmt, ACTION_DELETE);
}
int ast_filerename(const char *filename, const char *filename2, const char *fmt)
{
- return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
+ return filehelper(filename, filename2, fmt, ACTION_RENAME);
}
int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
{
- return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
+ return filehelper(filename, filename2, fmt, ACTION_COPY);
}
int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
@@ -966,7 +1022,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
vfs = ast_openvstream(chan, filename, preflang);
if (vfs) {
- ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_getformatname(vfs->fmt->format));
+ ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_getformatname(&vfs->fmt->format));
}
if (ast_test_flag(chan, AST_FLAG_MASQ_NOSTREAM))
@@ -978,7 +1034,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
res = ast_playstream(fs);
if (!res && vfs)
res = ast_playstream(vfs);
- ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", chan->name, filename, ast_getformatname(chan->writeformat), preflang ? preflang : "default");
+ ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", chan->name, filename, ast_getformatname(&chan->writeformat), preflang ? preflang : "default");
return res;
}
@@ -986,7 +1042,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
{
FILE *bfile;
- struct ast_format *f;
+ struct ast_format_def *f;
struct ast_filestream *fs = NULL;
char *fn;
int format_found = 0;
@@ -1036,7 +1092,7 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
int fd, myflags = 0;
/* compiler claims this variable can be used before initialization... */
FILE *bfile = NULL;
- struct ast_format *f;
+ struct ast_format_def *f;
struct ast_filestream *fs = NULL;
char *buf = NULL;
size_t size = 0;
@@ -1359,8 +1415,8 @@ int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *
char *ast_format_str_reduce(char *fmts)
{
- struct ast_format *f;
- struct ast_format *fmts_ptr[AST_MAX_FORMATS];
+ struct ast_format_def *f;
+ struct ast_format_def *fmts_ptr[AST_MAX_FORMATS];
char *fmts_str[AST_MAX_FORMATS];
char *stringp, *type;
char *orig = fmts;
@@ -1437,7 +1493,7 @@ static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd,
{
#define FORMAT "%-10s %-10s %-20s\n"
#define FORMAT2 "%-10s %-10s %-20s\n"
- struct ast_format *f;
+ struct ast_format_def *f;
int count_fmt = 0;
switch (cmd) {
@@ -1459,7 +1515,7 @@ static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd,
AST_RWLIST_RDLOCK(&formats);
AST_RWLIST_TRAVERSE(&formats, f, list) {
- ast_cli(a->fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
+ ast_cli(a->fd, FORMAT2, ast_getformatname(&f->format), f->name, f->exts);
count_fmt++;
}
AST_RWLIST_UNLOCK(&formats);
diff --git a/main/format.c b/main/format.c
new file mode 100644
index 000000000..d77d244a6
--- /dev/null
+++ b/main/format.c
@@ -0,0 +1,558 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Format API
+ *
+ * \author David Vossel <dvossel@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
+
+#include "asterisk/_private.h"
+#include "asterisk/version.h"
+#include "asterisk/format.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/lock.h"
+
+/*! This is the container for all the format attribute interfaces.
+ * An ao2 container was chosen for fast lookup. */
+static struct ao2_container *interfaces;
+
+/*! This is the lock used to protect the interfaces container. Yes, ao2_containers
+ * do have their own locking, but we need the capability of performing read/write
+ * locks on this specific container. */
+static ast_rwlock_t ilock;
+
+/*! a wrapper is used put interfaces into the ao2 container. */
+struct interface_ao2_wrapper {
+ enum ast_format_id id;
+ const struct ast_format_attr_interface *interface;
+ /*! a read write lock must be used to protect the wrapper instead
+ * of the ao2 lock. */
+ ast_rwlock_t wraplock;
+};
+
+static int interface_cmp_cb(void *obj, void *arg, int flags)
+{
+ struct interface_ao2_wrapper *wrapper1 = obj;
+ struct interface_ao2_wrapper *wrapper2 = arg;
+
+ return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static int interface_hash_cb(const void *obj, const int flags)
+{
+ const struct interface_ao2_wrapper *wrapper = obj;
+ return wrapper->id;
+}
+
+static void interface_destroy_cb(void *obj)
+{
+ struct interface_ao2_wrapper *wrapper = obj;
+ ast_rwlock_destroy(&wrapper->wraplock);
+}
+
+void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
+{
+ memcpy(dst, src, sizeof(struct ast_format));
+}
+
+void ast_format_set_video_mark(struct ast_format *format)
+{
+ format->fattr.rtp_marker_bit = 1;
+}
+
+int ast_format_get_video_mark(const struct ast_format *format)
+{
+ return format->fattr.rtp_marker_bit;
+}
+
+static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
+{
+ struct interface_ao2_wrapper *wrapper;
+ struct interface_ao2_wrapper tmp_wrapper = {
+ .id = format->id,
+ };
+
+ ast_rwlock_rdlock(&ilock);
+ if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
+ ast_rwlock_unlock(&ilock);
+ return NULL;
+ }
+ ast_rwlock_unlock(&ilock);
+
+ return wrapper;
+}
+
+/*! \internal
+ * \brief set format attributes using an interface
+ */
+static int format_set_helper(struct ast_format *format, va_list ap)
+{
+ struct interface_ao2_wrapper *wrapper;
+
+ if (!(wrapper = find_interface(format))) {
+ ast_log(LOG_WARNING, "Could not find format interface to set.\n");
+ return -1;
+ }
+
+ ast_rwlock_rdlock(&wrapper->wraplock);
+ if (!wrapper->interface || !wrapper->interface->format_attr_set) {
+ ast_rwlock_unlock(&wrapper->wraplock);
+ ao2_ref(wrapper, -1);
+ return -1;
+ }
+
+ wrapper->interface->format_attr_set(&format->fattr, ap);
+
+ ast_rwlock_unlock(&wrapper->wraplock);
+ ao2_ref(wrapper, -1);
+
+ return 0;
+}
+
+struct ast_format *ast_format_append(struct ast_format *format, ... )
+{
+ va_list ap;
+ va_start(ap, format);
+ format_set_helper(format, ap);
+ va_end(ap);
+
+ return format;
+}
+
+struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
+{
+ /* initialize the structure before setting it. */
+ ast_format_clear(format);
+
+ format->id = id;
+
+ if (set_attributes) {
+ va_list ap;
+ va_start(ap, set_attributes);
+ format_set_helper(format, ap);
+ va_end(ap);
+ }
+
+ return format;
+}
+
+void ast_format_clear(struct ast_format *format)
+{
+ format->id = 0;
+ memset(&format->fattr, 0, sizeof(format->fattr));
+}
+
+/*! \internal
+ * \brief determine if a list of attribute key value pairs are set on a format
+ */
+static int format_isset_helper(struct ast_format *format, va_list ap)
+{
+ int res;
+ struct interface_ao2_wrapper *wrapper;
+ struct ast_format tmp = {
+ .id = format->id,
+ .fattr = { { 0, }, },
+ };
+
+ if (!(wrapper = find_interface(format))) {
+ return -1;
+ }
+
+ ast_rwlock_rdlock(&wrapper->wraplock);
+ if (!wrapper->interface ||
+ !wrapper->interface->format_attr_set ||
+ !wrapper->interface->format_attr_cmp) {
+
+ ast_rwlock_unlock(&wrapper->wraplock);
+ ao2_ref(wrapper, -1);
+ return -1;
+ }
+
+ wrapper->interface->format_attr_set(&tmp.fattr, ap);
+
+ /* use our tmp structure to tell if the attributes are set or not */
+ res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr);
+
+ ast_rwlock_unlock(&wrapper->wraplock);
+ ao2_ref(wrapper, -1);
+
+ return (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
+}
+
+int ast_format_isset(struct ast_format *format, ... )
+{
+ va_list ap;
+ int res;
+
+ va_start(ap, format);
+ res = format_isset_helper(format, ap);
+ va_end(ap);
+ return res;
+}
+
+
+/*! \internal
+ * \brief cmp format attributes using an interface
+ */
+static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
+{
+ enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
+ struct interface_ao2_wrapper *wrapper;
+
+ if (!(wrapper = find_interface(format1))) {
+ return res;
+ }
+
+ ast_rwlock_rdlock(&wrapper->wraplock);
+ if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
+ ast_rwlock_unlock(&wrapper->wraplock);
+ ao2_ref(wrapper, -1);
+ return res;
+ }
+
+ res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
+
+ ast_rwlock_unlock(&wrapper->wraplock);
+ ao2_ref(wrapper, -1);
+
+ return res;
+}
+
+enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
+{
+ if (format1->id != format2->id) {
+ return AST_FORMAT_CMP_NOT_EQUAL;
+ }
+
+ return format_cmp_helper(format1, format2);
+}
+
+/*! \internal
+ * \brief get joint format attributes using an interface
+ */
+static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
+{
+ int res = 0;
+ struct interface_ao2_wrapper *wrapper;
+
+ if (!(wrapper = find_interface(format1))) {
+ /* if no interface is present, we assume formats are joint by id alone */
+ return res;
+ }
+
+ ast_rwlock_rdlock(&wrapper->wraplock);
+ if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
+ res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
+ }
+ ast_rwlock_unlock(&wrapper->wraplock);
+
+ ao2_ref(wrapper, -1);
+
+ return res;
+}
+
+int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
+{
+ if (format1->id != format2->id) {
+ return -1;
+ }
+ result->id = format1->id;
+ return format_joint_helper(format1, format2, result);
+}
+
+
+uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
+{
+ switch (id) {
+ /*! G.723.1 compression */
+ case AST_FORMAT_G723_1:
+ return (1ULL << 0);
+ /*! GSM compression */
+ case AST_FORMAT_GSM:
+ return (1ULL << 1);
+ /*! Raw mu-law data (G.711) */
+ case AST_FORMAT_ULAW:
+ return (1ULL << 2);
+ /*! Raw A-law data (G.711) */
+ case AST_FORMAT_ALAW:
+ return (1ULL << 3);
+ /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
+ case AST_FORMAT_G726_AAL2:
+ return (1ULL << 4);
+ /*! ADPCM (IMA) */
+ case AST_FORMAT_ADPCM:
+ return (1ULL << 5);
+ /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+ case AST_FORMAT_SLINEAR:
+ return (1ULL << 6);
+ /*! LPC10, 180 samples/frame */
+ case AST_FORMAT_LPC10:
+ return (1ULL << 7);
+ /*! G.729A audio */
+ case AST_FORMAT_G729A:
+ return (1ULL << 8);
+ /*! SpeeX Free Compression */
+ case AST_FORMAT_SPEEX:
+ return (1ULL << 9);
+ /*! iLBC Free Compression */
+ case AST_FORMAT_ILBC:
+ return (1ULL << 10);
+ /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
+ case AST_FORMAT_G726:
+ return (1ULL << 11);
+ /*! G.722 */
+ case AST_FORMAT_G722:
+ return (1ULL << 12);
+ /*! G.722.1 (also known as Siren7, 32kbps assumed) */
+ case AST_FORMAT_SIREN7:
+ return (1ULL << 13);
+ /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
+ case AST_FORMAT_SIREN14:
+ return (1ULL << 14);
+ /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
+ case AST_FORMAT_SLINEAR16:
+ return (1ULL << 15);
+ /*! G.719 (64 kbps assumed) */
+ case AST_FORMAT_G719:
+ return (1ULL << 32);
+ /*! SpeeX Wideband (16kHz) Free Compression */
+ case AST_FORMAT_SPEEX16:
+ return (1ULL << 33);
+ /*! Raw mu-law data (G.711) */
+ case AST_FORMAT_TESTLAW:
+ return (1ULL << 47);
+
+ /*! H.261 Video */
+ case AST_FORMAT_H261:
+ return (1ULL << 18);
+ /*! H.263 Video */
+ case AST_FORMAT_H263:
+ return (1ULL << 19);
+ /*! H.263+ Video */
+ case AST_FORMAT_H263_PLUS:
+ return (1ULL << 20);
+ /*! H.264 Video */
+ case AST_FORMAT_H264:
+ return (1ULL << 21);
+ /*! MPEG4 Video */
+ case AST_FORMAT_MP4_VIDEO:
+ return (1ULL << 22);
+
+ /*! JPEG Images */
+ case AST_FORMAT_JPEG:
+ return (1ULL << 16);
+ /*! PNG Images */
+ case AST_FORMAT_PNG:
+ return (1ULL << 17);
+
+ /*! T.140 RED Text format RFC 4103 */
+ case AST_FORMAT_T140RED:
+ return (1ULL << 26);
+ /*! T.140 Text format - ITU T.140, RFC 4103 */
+ case AST_FORMAT_T140:
+ return (1ULL << 27);
+ }
+
+ return 0;
+
+}
+uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
+{
+ return ast_format_id_to_old_bitfield(format->id);
+}
+
+struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
+{
+ switch (src) {
+ /*! G.723.1 compression */
+ case (1ULL << 0):
+ return ast_format_set(dst, AST_FORMAT_G723_1, 0);
+ /*! GSM compression */
+ case (1ULL << 1):
+ return ast_format_set(dst, AST_FORMAT_GSM, 0);
+ /*! Raw mu-law data (G.711) */
+ case (1ULL << 2):
+ return ast_format_set(dst, AST_FORMAT_ULAW, 0);
+ /*! Raw A-law data (G.711) */
+ case (1ULL << 3):
+ return ast_format_set(dst, AST_FORMAT_ALAW, 0);
+ /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
+ case (1ULL << 4):
+ return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
+ /*! ADPCM (IMA) */
+ case (1ULL << 5):
+ return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
+ /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+ case (1ULL << 6):
+ return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
+ /*! LPC10, 180 samples/frame */
+ case (1ULL << 7):
+ return ast_format_set(dst, AST_FORMAT_LPC10, 0);
+ /*! G.729A audio */
+ case (1ULL << 8):
+ return ast_format_set(dst, AST_FORMAT_G729A, 0);
+ /*! SpeeX Free Compression */
+ case (1ULL << 9):
+ return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
+ /*! iLBC Free Compression */
+ case (1ULL << 10):
+ return ast_format_set(dst, AST_FORMAT_ILBC, 0);
+ /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
+ case (1ULL << 11):
+ return ast_format_set(dst, AST_FORMAT_G726, 0);
+ /*! G.722 */
+ case (1ULL << 12):
+ return ast_format_set(dst, AST_FORMAT_G722, 0);
+ /*! G.722.1 (also known as Siren7, 32kbps assumed) */
+ case (1ULL << 13):
+ return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
+ /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
+ case (1ULL << 14):
+ return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
+ /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
+ case (1ULL << 15):
+ return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
+ /*! G.719 (64 kbps assumed) */
+ case (1ULL << 32):
+ return ast_format_set(dst, AST_FORMAT_G719, 0);
+ /*! SpeeX Wideband (16kHz) Free Compression */
+ case (1ULL << 33):
+ return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
+ /*! Raw mu-law data (G.711) */
+ case (1ULL << 47):
+ return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
+
+ /*! H.261 Video */
+ case (1ULL << 18):
+ return ast_format_set(dst, AST_FORMAT_H261, 0);
+ /*! H.263 Video */
+ case (1ULL << 19):
+ return ast_format_set(dst, AST_FORMAT_H263, 0);
+ /*! H.263+ Video */
+ case (1ULL << 20):
+ return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
+ /*! H.264 Video */
+ case (1ULL << 21):
+ return ast_format_set(dst, AST_FORMAT_H264, 0);
+ /*! MPEG4 Video */
+ case (1ULL << 22):
+ return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
+
+ /*! JPEG Images */
+ case (1ULL << 16):
+ return ast_format_set(dst, AST_FORMAT_JPEG, 0);
+ /*! PNG Images */
+ case (1ULL << 17):
+ return ast_format_set(dst, AST_FORMAT_PNG, 0);
+
+ /*! T.140 RED Text format RFC 4103 */
+ case (1ULL << 26):
+ return ast_format_set(dst, AST_FORMAT_T140RED, 0);
+ /*! T.140 Text format - ITU T.140, RFC 4103 */
+ case (1ULL << 27):
+ return ast_format_set(dst, AST_FORMAT_T140, 0);
+ }
+ ast_format_clear(dst);
+ return NULL;
+}
+
+enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
+{
+ struct ast_format dst;
+ if (ast_format_from_old_bitfield(&dst, src)) {
+ return dst.id;
+ }
+ return 0;
+}
+
+int ast_format_attr_init()
+{
+ if (ast_rwlock_init(&ilock)) {
+ return -1;
+ }
+ if (!(interfaces = ao2_container_alloc(283, interface_hash_cb, interface_cmp_cb))) {
+ ast_rwlock_destroy(&ilock);
+ return -1;
+ }
+ return 0;
+}
+
+int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
+{
+ struct interface_ao2_wrapper *wrapper;
+ struct interface_ao2_wrapper tmp_wrapper = {
+ .id = interface->id,
+ };
+
+ /* check for duplicates first*/
+ ast_rwlock_wrlock(&ilock);
+ if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
+ ast_rwlock_unlock(&ilock);
+ ast_log(LOG_WARNING, "Can not register attribute interface for format id %d, interface already exists.\n", interface->id);
+ ao2_ref(wrapper, -1);
+ return -1;
+ }
+ ast_rwlock_unlock(&ilock);
+
+ if (!(wrapper = ao2_alloc(sizeof(*wrapper), interface_destroy_cb))) {
+ return -1;
+ }
+
+ wrapper->interface = interface;
+ wrapper->id = interface->id;
+ ast_rwlock_init(&wrapper->wraplock);
+
+ /* use the write lock whenever the interface container is modified */
+ ast_rwlock_wrlock(&ilock);
+ ao2_link(interfaces, wrapper);
+ ast_rwlock_unlock(&ilock);
+
+ ao2_ref(wrapper, -1);
+
+ return 0;
+}
+
+int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
+{
+ struct interface_ao2_wrapper *wrapper;
+ struct interface_ao2_wrapper tmp_wrapper = {
+ .id = interface->id,
+ };
+
+ /* use the write lock whenever the interface container is modified */
+ ast_rwlock_wrlock(&ilock);
+ if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK | OBJ_NOLOCK)))) {
+ ast_rwlock_unlock(&ilock);
+ return -1;
+ }
+ ast_rwlock_unlock(&ilock);
+
+ ast_rwlock_wrlock(&wrapper->wraplock);
+ wrapper->interface = NULL;
+ ast_rwlock_unlock(&wrapper->wraplock);
+
+ ao2_ref(wrapper, -1);
+
+ return 0;
+}
diff --git a/main/format_cap.c b/main/format_cap.c
new file mode 100644
index 000000000..1d566050f
--- /dev/null
+++ b/main/format_cap.c
@@ -0,0 +1,545 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Format Capability API
+ *
+ * \author David Vossel <dvossel@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
+
+#include "asterisk/_private.h"
+#include "asterisk/version.h"
+#include "asterisk/format.h"
+#include "asterisk/format_cap.h"
+#include "asterisk/frame.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/utils.h"
+
+
+struct ast_format_cap {
+ /* The capabilities structure is just an ao2 container of ast_formats */
+ struct ao2_container *formats;
+ struct ao2_iterator it;
+ int nolock;
+};
+
+/*! format exists within capabilities structure if it is identical to
+ * another format, or if the format is a proper subset of another format. */
+static int cmp_cb(void *obj, void *arg, int flags)
+{
+ struct ast_format *format1 = arg;
+ struct ast_format *format2 = obj;
+ enum ast_format_cmp_res res = ast_format_cmp(format1, format2);
+
+ return ((res == AST_FORMAT_CMP_EQUAL) ||
+ (res == AST_FORMAT_CMP_SUBSET)) ?
+ CMP_MATCH | CMP_STOP :
+ 0;
+}
+
+static int hash_cb(const void *obj, const int flags)
+{
+ const struct ast_format *format = obj;
+ return format->id;
+}
+
+static struct ast_format_cap *cap_alloc_helper(int nolock)
+{
+ struct ast_format_cap *cap = ast_calloc(1, sizeof(*cap));
+
+ if (!cap) {
+ return NULL;
+ }
+ cap->nolock = nolock ? OBJ_NOLOCK : 0;
+ if (!(cap->formats = ao2_container_alloc(283, hash_cb, cmp_cb))) {
+ ast_free(cap);
+ return NULL;
+ }
+
+ return cap;
+}
+
+struct ast_format_cap *ast_format_cap_alloc_nolock(void)
+{
+ return cap_alloc_helper(1);
+}
+
+struct ast_format_cap *ast_format_cap_alloc(void)
+{
+ return cap_alloc_helper(0);
+}
+
+void *ast_format_cap_destroy(struct ast_format_cap *cap)
+{
+ if (!cap) {
+ return NULL;
+ }
+ ao2_ref(cap->formats, -1);
+ ast_free(cap);
+ return NULL;
+}
+
+void ast_format_cap_add(struct ast_format_cap *cap, struct ast_format *format)
+{
+ struct ast_format *fnew;
+
+ if (!format || !format->id) {
+ return;
+ }
+ if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
+ return;
+ }
+ ast_format_copy(fnew, format);
+ if (cap->nolock) {
+ ao2_link_nolock(cap->formats, fnew);
+ } else {
+ ao2_link(cap->formats, fnew);
+ }
+ ao2_ref(fnew, -1);
+}
+
+void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type)
+{
+ int x;
+ size_t f_len = 0;
+ struct ast_format tmp_fmt;
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+
+ for (x = 0; x < f_len; x++) {
+ if (AST_FORMAT_GET_TYPE(f_list[x].id) == type) {
+ ast_format_cap_add(cap, ast_format_set(&tmp_fmt, f_list[x].id, 0));
+ }
+ }
+}
+
+void ast_format_cap_add_all(struct ast_format_cap *cap)
+{
+ int x;
+ size_t f_len = 0;
+ struct ast_format tmp_fmt;
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+
+ for (x = 0; x < f_len; x++) {
+ ast_format_cap_add(cap, ast_format_set(&tmp_fmt, f_list[x].id, 0));
+ }
+}
+
+static int append_cb(void *obj, void *arg, int flag)
+{
+ struct ast_format_cap *result = (struct ast_format_cap *) arg;
+ struct ast_format *format = (struct ast_format *) obj;
+
+ if (!ast_format_cap_iscompatible(result, format)) {
+ ast_format_cap_add(result, format);
+ }
+
+ return 0;
+}
+
+void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
+{
+ ao2_callback(src->formats, OBJ_NODATA | src->nolock, append_cb, dst);
+}
+
+static int copy_cb(void *obj, void *arg, int flag)
+{
+ struct ast_format_cap *result = (struct ast_format_cap *) arg;
+ struct ast_format *format = (struct ast_format *) obj;
+
+ ast_format_cap_add(result, format);
+ return 0;
+}
+
+void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
+{
+ ast_format_cap_remove_all(dst);
+ ao2_callback(src->formats, OBJ_NODATA | src->nolock, copy_cb, dst);
+}
+
+struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
+{
+ struct ast_format_cap *dst;
+ if (cap->nolock) {
+ dst = ast_format_cap_alloc_nolock();
+ } else {
+ dst = ast_format_cap_alloc();
+ }
+ if (!dst) {
+ return NULL;
+ }
+ ao2_callback(cap->formats, OBJ_NODATA | cap->nolock, copy_cb, dst);
+ return dst;
+}
+
+int ast_format_cap_is_empty(const struct ast_format_cap *cap)
+{
+ if (!cap) {
+ return 1;
+ }
+ return ao2_container_count(cap->formats) == 0 ? 1 : 0;
+}
+
+static int find_exact_cb(void *obj, void *arg, int flag)
+{
+ struct ast_format *format1 = (struct ast_format *) arg;
+ struct ast_format *format2 = (struct ast_format *) obj;
+
+ return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0;
+}
+
+int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
+{
+ struct ast_format *fremove;
+ fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK | cap->nolock, find_exact_cb, format);
+
+ if (fremove) {
+ ao2_ref(fremove, -1);
+ return 0;
+ }
+
+ return -1;
+}
+
+struct multiple_by_id_data {
+ struct ast_format *format;
+ int match_found;
+};
+
+static int multiple_by_id_cb(void *obj, void *arg, int flag)
+{
+ struct multiple_by_id_data *data = arg;
+ struct ast_format *format = obj;
+ int res;
+
+ res = (format->id == data->format->id) ? CMP_MATCH : 0;
+ if (res) {
+ data->match_found = 1;
+ }
+
+ return res;
+}
+
+int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id)
+{
+ struct ast_format format = {
+ .id = id,
+ };
+ struct multiple_by_id_data data = {
+ .format = &format,
+ .match_found = 0,
+ };
+
+ ao2_callback(cap->formats,
+ OBJ_NODATA | cap->nolock | OBJ_MULTIPLE | OBJ_UNLINK,
+ multiple_by_id_cb,
+ &data);
+
+ /* match_found will be set if at least one item was removed */
+ if (data.match_found) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static int multiple_by_type_cb(void *obj, void *arg, int flag)
+{
+ int *type = arg;
+ struct ast_format *format = obj;
+ return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0;
+}
+
+void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
+{
+ ao2_callback(cap->formats,
+ OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE | cap->nolock,
+ multiple_by_type_cb,
+ &type);
+}
+
+void ast_format_cap_remove_all(struct ast_format_cap *cap)
+{
+ ao2_callback(cap->formats, OBJ_NODATA | cap->nolock | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
+}
+
+void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
+{
+ ast_format_cap_remove_all(cap);
+ ast_format_cap_add(cap, format);
+}
+
+int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
+{
+ struct ast_format *f;
+ struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
+ f = ao2_find(tmp_cap->formats, (struct ast_format *) format, OBJ_POINTER | tmp_cap->nolock);
+
+ if (f) {
+ ao2_ref(f, -1);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*! \internal
+ * \brief this struct is just used for the ast_format_cap_joint function so we can provide
+ * both a format and a result ast_format_cap structure as arguments to the find_joint_cb
+ * ao2 callback function.
+ */
+struct find_joint_data {
+ /*! format to compare to for joint capabilities */
+ struct ast_format *format;
+ /*! if joint formmat exists with above format, add it to the result container */
+ struct ast_format_cap *joint_cap;
+ int joint_found;
+};
+
+static int find_joint_cb(void *obj, void *arg, int flag)
+{
+ struct ast_format *format = obj;
+ struct find_joint_data *data = arg;
+
+ struct ast_format tmp = { 0, };
+ if (!ast_format_joint(format, data->format, &tmp)) {
+ if (data->joint_cap) {
+ ast_format_cap_add(data->joint_cap, &tmp);
+ }
+ data->joint_found++;
+ }
+
+ return 0;
+}
+
+int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
+{
+ struct ao2_iterator it;
+ struct ast_format *tmp;
+ struct find_joint_data data = {
+ .joint_found = 0,
+ .joint_cap = NULL,
+ };
+
+ it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
+ while ((tmp = ao2_iterator_next(&it))) {
+ data.format = tmp;
+ ao2_callback(cap2->formats,
+ OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
+ find_joint_cb,
+ &data);
+ ao2_ref(tmp, -1);
+ }
+ ao2_iterator_destroy(&it);
+
+ return data.joint_found ? 1 : 0;
+}
+
+int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
+{
+ struct ao2_iterator it;
+ struct ast_format *tmp;
+
+ if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
+ return 0; /* if they are not the same size, they are not identical */
+ }
+
+ it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
+ while ((tmp = ao2_iterator_next(&it))) {
+ if (!ast_format_cap_iscompatible(cap2, tmp)) {
+ ao2_ref(tmp, -1);
+ ao2_iterator_destroy(&it);
+ return 0;
+ }
+ ao2_ref(tmp, -1);
+ }
+ ao2_iterator_destroy(&it);
+
+ return 1;
+}
+
+struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
+{
+ struct ao2_iterator it;
+ struct ast_format_cap *result = ast_format_cap_alloc_nolock();
+ struct ast_format *tmp;
+ struct find_joint_data data = {
+ .joint_found = 0,
+ .joint_cap = result,
+ };
+ if (!result) {
+ return NULL;
+ }
+
+ it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
+ while ((tmp = ao2_iterator_next(&it))) {
+ data.format = tmp;
+ ao2_callback(cap2->formats,
+ OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
+ find_joint_cb,
+ &data);
+ ao2_ref(tmp, -1);
+ }
+ ao2_iterator_destroy(&it);
+
+ if (ao2_container_count(result->formats)) {
+ return result;
+ }
+
+ result = ast_format_cap_destroy(result);
+ return NULL;
+}
+
+int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
+{
+ struct ao2_iterator it;
+ struct ast_format *tmp;
+ struct find_joint_data data = {
+ .joint_cap = result,
+ .joint_found = 0,
+ };
+
+ ast_format_cap_remove_all(result);
+ it = ao2_iterator_init(cap1->formats, cap2->nolock ? AO2_ITERATOR_DONTLOCK : 0);
+ while ((tmp = ao2_iterator_next(&it))) {
+ data.format = tmp;
+ ao2_callback(cap2->formats,
+ OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
+ find_joint_cb,
+ &data);
+ ao2_ref(tmp, -1);
+ }
+ ao2_iterator_destroy(&it);
+
+ return ao2_container_count(result->formats) ? 1 : 0;
+}
+
+struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
+{
+ struct ao2_iterator it;
+ struct ast_format_cap *result = ast_format_cap_alloc_nolock();
+ struct ast_format *tmp;
+
+ if (!result) {
+ return NULL;
+ }
+
+ /* for each format in cap1, see if that format is
+ * compatible with cap2. If so copy it to the result */
+ it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
+ while ((tmp = ao2_iterator_next(&it))) {
+ if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
+ /* copy format */
+ ast_format_cap_add(result, tmp);
+ }
+ ao2_ref(tmp, -1);
+ }
+ ao2_iterator_destroy(&it);
+
+ if (ao2_container_count(result->formats)) {
+ return result;
+ }
+ result = ast_format_cap_destroy(result);
+
+ /* Remember to always free the NULL before returning it. */
+ ast_free(NULL);
+ return NULL;
+}
+
+
+int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
+{
+ struct ao2_iterator it;
+ struct ast_format *tmp;
+
+ it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
+ while ((tmp = ao2_iterator_next(&it))) {
+ if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
+ ao2_ref(tmp, -1);
+ ao2_iterator_destroy(&it);
+ return 1;
+ }
+ ao2_ref(tmp, -1);
+ }
+ ao2_iterator_destroy(&it);
+
+ return 0;
+}
+
+void ast_format_cap_iter_start(struct ast_format_cap *cap)
+{
+ if (!cap->nolock) {
+ ao2_lock(cap->formats);
+ }
+ cap->it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
+}
+
+void ast_format_cap_iter_end(struct ast_format_cap *cap)
+{
+ ao2_iterator_destroy(&cap->it);
+ if (!cap->nolock) {
+ ao2_unlock(cap->formats);
+ }
+}
+
+int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
+{
+ struct ast_format *tmp = ao2_iterator_next(&cap->it);
+
+ if (!tmp) {
+ return -1;
+ }
+ ast_format_copy(format, tmp);
+ ao2_ref(tmp, -1);
+
+ return 0;
+}
+
+uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
+{
+ uint64_t res = 0;
+ struct ao2_iterator it;
+ struct ast_format *tmp;
+
+ it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
+ while ((tmp = ao2_iterator_next(&it))) {
+ res |= ast_format_to_old_bitfield(tmp);
+ ao2_ref(tmp, -1);
+ }
+ ao2_iterator_destroy(&it);
+ return res;
+}
+
+void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
+{
+ uint64_t tmp = 0;
+ int x;
+ struct ast_format tmp_format = { 0, };
+
+ ast_format_cap_remove_all(dst);
+ for (x = 0; x < 64; x++) {
+ tmp = (1ULL << x);
+ if (tmp & src) {
+ ast_format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));
+ }
+ }
+}
diff --git a/main/format_pref.c b/main/format_pref.c
new file mode 100644
index 000000000..26801b648
--- /dev/null
+++ b/main/format_pref.c
@@ -0,0 +1,320 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Format Preference API
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
+
+#include "asterisk/_private.h"
+#include "asterisk/version.h"
+#include "asterisk/frame.h"
+#include "asterisk/channel.h"
+#include "asterisk/utils.h"
+
+void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
+{
+ size_t f_len;
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+ int x, differential = (int) 'A', mem;
+ char *from, *to;
+
+ /* TODO re-evaluate this function. It is using the order of the formats specified
+ * in the global format list in a way that may not be safe. */
+ if (right) {
+ from = pref->order;
+ to = buf;
+ mem = size;
+ } else {
+ to = pref->order;
+ from = buf;
+ mem = AST_CODEC_PREF_SIZE;
+ }
+
+ memset(to, 0, mem);
+ for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+ if (!from[x]) {
+ break;
+ }
+ to[x] = right ? (from[x] + differential) : (from[x] - differential);
+ if (!right && to[x] && (to[x] < f_len)) {
+ ast_format_set(&pref->formats[x], f_list[to[x]-1].id , 0);
+ }
+ }
+}
+
+int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
+{
+ int x;
+ struct ast_format format;
+ size_t total_len, slen;
+ char *formatname;
+
+ memset(buf, 0, size);
+ total_len = size;
+ buf[0] = '(';
+ total_len--;
+ for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+ if (total_len <= 0)
+ break;
+ if (!(ast_codec_pref_index(pref, x, &format)))
+ break;
+ if ((formatname = ast_getformatname(&format))) {
+ slen = strlen(formatname);
+ if (slen > total_len)
+ break;
+ strncat(buf, formatname, total_len - 1); /* safe */
+ total_len -= slen;
+ }
+ if (total_len && x < AST_CODEC_PREF_SIZE - 1 && ast_codec_pref_index(pref, x + 1, &format)) {
+ strncat(buf, "|", total_len - 1); /* safe */
+ total_len--;
+ }
+ }
+ if (total_len) {
+ strncat(buf, ")", total_len - 1); /* safe */
+ total_len--;
+ }
+
+ return size - total_len;
+}
+
+struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result)
+{
+ if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) {
+ ast_format_copy(result, &pref->formats[idx]);
+ } else {
+ ast_format_clear(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+/*! \brief Remove codec from pref list */
+void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format)
+{
+ struct ast_codec_pref oldorder;
+ int x, y = 0;
+ size_t f_len = 0;
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+
+ if (!pref->order[0])
+ return;
+
+ memcpy(&oldorder, pref, sizeof(oldorder));
+ memset(pref, 0, sizeof(*pref));
+
+ for (x = 0; x < f_len; x++) {
+ if (!oldorder.order[x])
+ break;
+ if (f_list[oldorder.order[x]-1].id != format->id) {
+ pref->order[y] = oldorder.order[x];
+ ast_format_copy(&pref->formats[y], &oldorder.formats[x]);
+ pref->framing[y++] = oldorder.framing[x];
+ }
+ }
+}
+
+/*! \brief Append codec to list */
+int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format)
+{
+ int x, newindex = 0;
+ size_t f_len = 0;
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+
+ ast_codec_pref_remove(pref, format);
+
+ for (x = 0; x < f_len; x++) {
+ if (f_list[x].id == format->id) {
+ newindex = x + 1;
+ break;
+ }
+ }
+
+ if (newindex) {
+ for (x = 0; x < f_len; x++) {
+ if (!pref->order[x]) {
+ pref->order[x] = newindex;
+ ast_format_copy(&pref->formats[x], format);
+ break;
+ }
+ }
+ }
+
+ return x;
+}
+
+/*! \brief Prepend codec to list */
+void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing)
+{
+ int x, newindex = 0;
+ size_t f_len = 0;
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+
+ /* First step is to get the codecs "index number" */
+ for (x = 0; x < f_len; x++) {
+ if (f_list[x].id == format->id) {
+ newindex = x + 1;
+ break;
+ }
+ }
+ /* Done if its unknown */
+ if (!newindex)
+ return;
+
+ /* Now find any existing occurrence, or the end */
+ for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
+ if (!pref->order[x] || pref->order[x] == newindex)
+ break;
+ }
+
+ if (only_if_existing && !pref->order[x])
+ return;
+
+ /* Move down to make space to insert - either all the way to the end,
+ or as far as the existing location (which will be overwritten) */
+ for (; x > 0; x--) {
+ pref->order[x] = pref->order[x - 1];
+ pref->framing[x] = pref->framing[x - 1];
+ ast_format_copy(&pref->formats[x], &pref->formats[x - 1]);
+ }
+
+ /* And insert the new entry */
+ pref->order[0] = newindex;
+ pref->framing[0] = 0; /* ? */
+ ast_format_copy(&pref->formats[0], format);
+}
+
+/*! \brief Set packet size for codec */
+int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems)
+{
+ int x, idx = -1;
+ size_t f_len = 0;
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+
+ for (x = 0; x < f_len; x++) {
+ if (f_list[x].id == format->id) {
+ idx = x;
+ break;
+ }
+ }
+
+ if (idx < 0)
+ return -1;
+
+ /* size validation */
+ if (!framems)
+ framems = f_list[idx].def_ms;
+
+ if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
+ framems -= framems % f_list[idx].inc_ms;
+
+ if (framems < f_list[idx].min_ms)
+ framems = f_list[idx].min_ms;
+
+ if (framems > f_list[idx].max_ms)
+ framems = f_list[idx].max_ms;
+
+ for (x = 0; x < f_len; x++) {
+ if (pref->order[x] == (idx + 1)) {
+ pref->framing[x] = framems;
+ break;
+ }
+ }
+
+ return x;
+}
+
+/*! \brief Get packet size for codec */
+struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format)
+{
+ int x, idx = -1, framems = 0;
+ struct ast_format_list fmt = { 0, };
+ size_t f_len = 0;
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+
+ for (x = 0; x < f_len; x++) {
+ if (f_list[x].id == format->id) {
+ fmt = f_list[x];
+ idx = x;
+ break;
+ }
+ }
+
+ for (x = 0; x < f_len; x++) {
+ if (pref->order[x] == (idx + 1)) {
+ framems = pref->framing[x];
+ break;
+ }
+ }
+
+ /* size validation */
+ if (!framems)
+ framems = f_list[idx].def_ms;
+
+ if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
+ framems -= framems % f_list[idx].inc_ms;
+
+ if (framems < f_list[idx].min_ms)
+ framems = f_list[idx].min_ms;
+
+ if (framems > f_list[idx].max_ms)
+ framems = f_list[idx].max_ms;
+
+ fmt.cur_ms = framems;
+
+ return fmt;
+}
+
+/*! \brief Pick a codec */
+struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result)
+{
+ int x, slot, found;
+ size_t f_len = 0;
+ struct ast_format tmp_fmt;
+
+ const struct ast_format_list *f_list = ast_get_format_list(&f_len);
+
+ ast_format_clear(result);
+
+ for (x = 0; x < f_len; x++) {
+ slot = pref->order[x];
+
+ if (!slot)
+ break;
+ if (ast_format_cap_iscompatible(cap, ast_format_set(&tmp_fmt, f_list[slot-1].id, 0))) {
+ found = 1; /*format is found and stored in tmp_fmt */
+ break;
+ }
+ }
+ if (found && (AST_FORMAT_GET_TYPE(tmp_fmt.id) == AST_FORMAT_TYPE_AUDIO)) {
+ ast_format_copy(result, &tmp_fmt);
+ return result;
+ }
+
+ ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
+
+ return find_best ? ast_best_codec(cap, result) : NULL;
+}
+
+
diff --git a/main/frame.c b/main/frame.c
index 9f599a991..840fa4b75 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -80,7 +80,7 @@ enum frame_type {
struct ast_smoother {
int size;
- format_t format;
+ struct ast_format format;
int flags;
float samplesperbyte;
unsigned int opt_needs_swap:1;
@@ -207,12 +207,12 @@ int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
return -1;
}
- if (!s->format) {
- s->format = f->subclass.codec;
+ if (!s->format.id) {
+ ast_format_copy(&s->format, &f->subclass.format);
s->samplesperbyte = (float)f->samples / (float)f->datalen;
- } else if (s->format != f->subclass.codec) {
+ } else if (ast_format_cmp(&s->format, &f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
ast_log(LOG_WARNING, "Smoother was working on %s format frames, now trying to feed %s?\n",
- ast_getformatname(s->format), ast_getformatname(f->subclass.codec));
+ ast_getformatname(&s->format), ast_getformatname(&f->subclass.format));
return -1;
}
if (s->len + f->datalen > SMOOTHER_SIZE) {
@@ -263,7 +263,7 @@ struct ast_frame *ast_smoother_read(struct ast_smoother *s)
len = s->len;
/* Make frame */
s->f.frametype = AST_FRAME_VOICE;
- s->f.subclass.codec = s->format;
+ ast_format_copy(&s->f.subclass.format, &s->format);
s->f.data.ptr = s->framedata + AST_FRIENDLY_OFFSET;
s->f.offset = AST_FRIENDLY_OFFSET;
s->f.datalen = len;
@@ -280,7 +280,7 @@ struct ast_frame *ast_smoother_read(struct ast_smoother *s)
memmove(s->data, s->data + len, s->len);
if (!ast_tvzero(s->delivery)) {
/* If we have delivery time, increment it, otherwise, leave it at 0 */
- s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(s->format)));
+ s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(&s->format)));
}
}
/* Return frame */
@@ -408,7 +408,7 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
return NULL;
}
out->frametype = fr->frametype;
- out->subclass.codec = fr->subclass.codec;
+ ast_format_copy(&out->subclass.format, &fr->subclass.format);
out->datalen = fr->datalen;
out->samples = fr->samples;
out->offset = fr->offset;
@@ -515,7 +515,7 @@ struct ast_frame *ast_frdup(const struct ast_frame *f)
}
out->frametype = f->frametype;
- out->subclass.codec = f->subclass.codec;
+ ast_format_copy(&out->subclass.format, &f->subclass.format);
out->datalen = f->datalen;
out->samples = f->samples;
out->delivery = f->delivery;
@@ -566,12 +566,12 @@ const struct ast_format_list *ast_get_format_list(size_t *size)
return AST_FORMAT_LIST;
}
-char* ast_getformatname(format_t format)
+char* ast_getformatname(struct ast_format *format)
{
int x;
char *ret = "unknown";
for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].bits == format) {
+ if (AST_FORMAT_LIST[x].id == format->id) {
ret = AST_FORMAT_LIST[x].name;
break;
}
@@ -579,21 +579,23 @@ char* ast_getformatname(format_t format)
return ret;
}
-char *ast_getformatname_multiple(char *buf, size_t size, format_t format)
+char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
{
int x;
unsigned len;
char *start, *end = buf;
+ struct ast_format tmp_fmt;
if (!size)
return buf;
- snprintf(end, size, "0x%llx (", (unsigned long long) format);
+ snprintf(end, size, "(");
len = strlen(end);
end += len;
size -= len;
start = end;
for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].bits & format) {
+ ast_format_set(&tmp_fmt, AST_FORMAT_LIST[x].id, 0);
+ if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
snprintf(end, size, "%s|", AST_FORMAT_LIST[x].name);
len = strlen(end);
end += len;
@@ -629,31 +631,28 @@ static const char *ast_expand_codec_alias(const char *in)
return in;
}
-format_t ast_getformatbyname(const char *name)
+struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
{
- int x, all;
- format_t format = 0;
+ int x;
- all = strcasecmp(name, "all") ? 0 : 1;
for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (all ||
- !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
- !strcasecmp(AST_FORMAT_LIST[x].name, ast_expand_codec_alias(name))) {
- format |= AST_FORMAT_LIST[x].bits;
- if (!all)
- break;
+ if (!strcasecmp(AST_FORMAT_LIST[x].name,name) ||
+ !strcasecmp(AST_FORMAT_LIST[x].name, ast_expand_codec_alias(name))) {
+
+ ast_format_set(result, AST_FORMAT_LIST[x].id, 0);
+ return result;
}
}
- return format;
+ return NULL;
}
-char *ast_codec2str(format_t codec)
+char *ast_codec2str(struct ast_format *format)
{
int x;
char *ret = "unknown";
for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].bits == codec) {
+ if (AST_FORMAT_LIST[x].id == format->id) {
ret = AST_FORMAT_LIST[x].desc;
break;
}
@@ -663,8 +662,7 @@ char *ast_codec2str(format_t codec)
static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
- int i, found=0;
- char hex[25];
+ int x, found=0;
switch (cmd) {
case CLI_INIT:
@@ -684,25 +682,25 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
"\tIt does not indicate anything about your configuration.\n");
- ast_cli(a->fd, "%19s %9s %20s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESCRIPTION");
+ ast_cli(a->fd, "%19s %8s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
- for (i = 0; i < 63; i++) {
+ for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
if (a->argc == 4) {
if (!strcasecmp(a->argv[3], "audio")) {
- if (!((1LL << i) & AST_FORMAT_AUDIO_MASK)) {
+ if (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) != AST_FORMAT_TYPE_AUDIO) {
continue;
}
} else if (!strcasecmp(a->argv[3], "video")) {
- if (!((1LL << i) & AST_FORMAT_VIDEO_MASK)) {
+ if (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) != AST_FORMAT_TYPE_VIDEO) {
continue;
}
} else if (!strcasecmp(a->argv[3], "image")) {
- if (i != 16 && i != 17) {
+ if (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) != AST_FORMAT_TYPE_IMAGE) {
continue;
}
} else if (!strcasecmp(a->argv[3], "text")) {
- if (!((1LL << i) & AST_FORMAT_TEXT_MASK)) {
+ if (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) != AST_FORMAT_TYPE_TEXT) {
continue;
}
} else {
@@ -710,14 +708,15 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
}
}
- snprintf(hex, sizeof(hex), "(0x%llx)", 1LL << i);
- ast_cli(a->fd, "%19llu (1 << %2d) %20s %5s %8s (%s)\n", 1LL << i, i, hex,
- ((1LL << i) & AST_FORMAT_AUDIO_MASK) ? "audio" :
- i == 16 || i == 17 ? "image" :
- ((1LL << i) & AST_FORMAT_VIDEO_MASK) ? "video" :
- ((1LL << i) & AST_FORMAT_TEXT_MASK) ? "text" :
+ ast_cli(a->fd, "%19u %5s %8s (%s)\n",
+ AST_FORMAT_LIST[x].id,
+ (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
+ (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) == AST_FORMAT_TYPE_TEXT) ? "image" :
+ (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) == AST_FORMAT_TYPE_VIDEO) ? "video" :
+ (AST_FORMAT_GET_TYPE(AST_FORMAT_LIST[x].id) == AST_FORMAT_TYPE_TEXT) ? "text" :
"(unk)",
- ast_getformatname(1LL << i), ast_codec2str(1LL << i));
+ AST_FORMAT_LIST[x].name,
+ AST_FORMAT_LIST[x].desc);
found = 1;
}
@@ -730,9 +729,9 @@ static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
- format_t codec;
- int i, found = 0;
- long long type_punned_codec;
+ enum ast_format_id format_id;
+ int x, found = 0;
+ int type_punned_codec;
switch (cmd) {
case CLI_INIT:
@@ -748,19 +747,21 @@ static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args
if (a->argc != 4)
return CLI_SHOWUSAGE;
- if (sscanf(a->argv[3], "%30lld", &type_punned_codec) != 1) {
+ if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
return CLI_SHOWUSAGE;
}
- codec = type_punned_codec;
+ format_id = type_punned_codec;
- for (i = 0; i < 63; i++)
- if (codec & (1LL << i)) {
+ for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
+ if (AST_FORMAT_LIST[x].id == format_id) {
found = 1;
- ast_cli(a->fd, "%11llu (1 << %2d) %s\n", 1LL << i, i, ast_codec2str(1LL << i));
+ ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, AST_FORMAT_LIST[x].desc);
+ break;
}
+ }
if (!found)
- ast_cli(a->fd, "Codec %lld not found\n", (long long) codec);
+ ast_cli(a->fd, "Codec %d not found\n", format_id);
return CLI_SUCCESS;
}
@@ -896,7 +897,7 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
break;
case AST_FRAME_IMAGE:
strcpy(ftype, "Image");
- snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass.codec));
+ snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(&f->subclass.format));
break;
case AST_FRAME_HTML:
strcpy(ftype, "HTML");
@@ -984,271 +985,11 @@ int init_framer(void)
return 0;
}
-void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
-{
- int x, differential = (int) 'A', mem;
- char *from, *to;
-
- if (right) {
- from = pref->order;
- to = buf;
- mem = size;
- } else {
- to = pref->order;
- from = buf;
- mem = sizeof(format_t) * 8;
- }
-
- memset(to, 0, mem);
- for (x = 0; x < sizeof(format_t) * 8; x++) {
- if (!from[x])
- break;
- to[x] = right ? (from[x] + differential) : (from[x] - differential);
- }
-}
-
-int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
-{
- int x;
- format_t codec;
- size_t total_len, slen;
- char *formatname;
-
- memset(buf, 0, size);
- total_len = size;
- buf[0] = '(';
- total_len--;
- for (x = 0; x < sizeof(format_t) * 8; x++) {
- if (total_len <= 0)
- break;
- if (!(codec = ast_codec_pref_index(pref,x)))
- break;
- if ((formatname = ast_getformatname(codec))) {
- slen = strlen(formatname);
- if (slen > total_len)
- break;
- strncat(buf, formatname, total_len - 1); /* safe */
- total_len -= slen;
- }
- if (total_len && x < sizeof(format_t) * 8 - 1 && ast_codec_pref_index(pref, x + 1)) {
- strncat(buf, "|", total_len - 1); /* safe */
- total_len--;
- }
- }
- if (total_len) {
- strncat(buf, ")", total_len - 1); /* safe */
- total_len--;
- }
-
- return size - total_len;
-}
-
-format_t ast_codec_pref_index(struct ast_codec_pref *pref, int idx)
-{
- int slot = 0;
-
- if ((idx >= 0) && (idx < sizeof(pref->order))) {
- slot = pref->order[idx];
- }
-
- return slot ? AST_FORMAT_LIST[slot - 1].bits : 0;
-}
-
-/*! \brief Remove codec from pref list */
-void ast_codec_pref_remove(struct ast_codec_pref *pref, format_t format)
-{
- struct ast_codec_pref oldorder;
- int x, y = 0;
- int slot;
- int size;
-
- if (!pref->order[0])
- return;
-
- memcpy(&oldorder, pref, sizeof(oldorder));
- memset(pref, 0, sizeof(*pref));
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- slot = oldorder.order[x];
- size = oldorder.framing[x];
- if (! slot)
- break;
- if (AST_FORMAT_LIST[slot-1].bits != format) {
- pref->order[y] = slot;
- pref->framing[y++] = size;
- }
- }
-}
-
-/*! \brief Append codec to list */
-int ast_codec_pref_append(struct ast_codec_pref *pref, format_t format)
-{
- int x, newindex = 0;
-
- ast_codec_pref_remove(pref, format);
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].bits == format) {
- newindex = x + 1;
- break;
- }
- }
-
- if (newindex) {
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (!pref->order[x]) {
- pref->order[x] = newindex;
- break;
- }
- }
- }
-
- return x;
-}
-
-/*! \brief Prepend codec to list */
-void ast_codec_pref_prepend(struct ast_codec_pref *pref, format_t format, int only_if_existing)
+int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing)
{
- int x, newindex = 0;
-
- /* First step is to get the codecs "index number" */
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].bits == format) {
- newindex = x + 1;
- break;
- }
- }
- /* Done if its unknown */
- if (!newindex)
- return;
-
- /* Now find any existing occurrence, or the end */
- for (x = 0; x < sizeof(format_t) * 8; x++) {
- if (!pref->order[x] || pref->order[x] == newindex)
- break;
- }
-
- if (only_if_existing && !pref->order[x])
- return;
-
- /* Move down to make space to insert - either all the way to the end,
- or as far as the existing location (which will be overwritten) */
- for (; x > 0; x--) {
- pref->order[x] = pref->order[x - 1];
- pref->framing[x] = pref->framing[x - 1];
- }
-
- /* And insert the new entry */
- pref->order[0] = newindex;
- pref->framing[0] = 0; /* ? */
-}
-
-/*! \brief Set packet size for codec */
-int ast_codec_pref_setsize(struct ast_codec_pref *pref, format_t format, int framems)
-{
- int x, idx = -1;
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].bits == format) {
- idx = x;
- break;
- }
- }
-
- if (idx < 0)
- return -1;
-
- /* size validation */
- if (!framems)
- framems = AST_FORMAT_LIST[idx].def_ms;
-
- if (AST_FORMAT_LIST[idx].inc_ms && framems % AST_FORMAT_LIST[idx].inc_ms) /* avoid division by zero */
- framems -= framems % AST_FORMAT_LIST[idx].inc_ms;
-
- if (framems < AST_FORMAT_LIST[idx].min_ms)
- framems = AST_FORMAT_LIST[idx].min_ms;
-
- if (framems > AST_FORMAT_LIST[idx].max_ms)
- framems = AST_FORMAT_LIST[idx].max_ms;
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (pref->order[x] == (idx + 1)) {
- pref->framing[x] = framems;
- break;
- }
- }
-
- return x;
-}
-
-/*! \brief Get packet size for codec */
-struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, format_t format)
-{
- int x, idx = -1, framems = 0;
- struct ast_format_list fmt = { 0, };
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (AST_FORMAT_LIST[x].bits == format) {
- fmt = AST_FORMAT_LIST[x];
- idx = x;
- break;
- }
- }
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- if (pref->order[x] == (idx + 1)) {
- framems = pref->framing[x];
- break;
- }
- }
-
- /* size validation */
- if (!framems)
- framems = AST_FORMAT_LIST[idx].def_ms;
-
- if (AST_FORMAT_LIST[idx].inc_ms && framems % AST_FORMAT_LIST[idx].inc_ms) /* avoid division by zero */
- framems -= framems % AST_FORMAT_LIST[idx].inc_ms;
-
- if (framems < AST_FORMAT_LIST[idx].min_ms)
- framems = AST_FORMAT_LIST[idx].min_ms;
-
- if (framems > AST_FORMAT_LIST[idx].max_ms)
- framems = AST_FORMAT_LIST[idx].max_ms;
-
- fmt.cur_ms = framems;
-
- return fmt;
-}
-
-/*! \brief Pick a codec */
-format_t ast_codec_choose(struct ast_codec_pref *pref, format_t formats, int find_best)
-{
- int x, slot;
- format_t ret = 0;
-
- for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
- slot = pref->order[x];
-
- if (!slot)
- break;
- if (formats & AST_FORMAT_LIST[slot-1].bits) {
- ret = AST_FORMAT_LIST[slot-1].bits;
- break;
- }
- }
- if (ret & AST_FORMAT_AUDIO_MASK)
- return ret;
-
- ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
-
- return find_best ? ast_best_codec(formats) : 0;
-}
-
-int ast_parse_allow_disallow(struct ast_codec_pref *pref, format_t *mask, const char *list, int allowing)
-{
- int errors = 0, framems = 0;
+ int errors = 0, framems = 0, all = 0;
char *parse = NULL, *this = NULL, *psize = NULL;
- format_t format = 0;
+ struct ast_format format;
parse = ast_strdupa(list);
while ((this = strsep(&parse, ","))) {
@@ -1263,30 +1004,38 @@ int ast_parse_allow_disallow(struct ast_codec_pref *pref, format_t *mask, const
ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
}
}
- if (!(format = ast_getformatbyname(this))) {
+ all = strcasecmp(this, "all") ? 0 : 1;
+
+ if (!all && !ast_getformatbyname(this, &format)) {
ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
errors++;
continue;
}
- if (mask) {
- if (allowing)
- *mask |= format;
- else
- *mask &= ~format;
+ if (cap) {
+ if (allowing) {
+ if (all) {
+ ast_format_cap_add_all(cap);
+ } else {
+ ast_format_cap_add(cap, &format);
+ }
+ } else {
+ if (all) {
+ ast_format_cap_remove_all(cap);
+ } else {
+ ast_format_cap_remove(cap, &format);
+ }
+ }
}
- /* Set up a preference list for audio. Do not include video in preferences
- since we can not transcode video and have to use whatever is offered
- */
- if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
- if (strcasecmp(this, "all")) {
+ if (pref) {
+ if (!all) {
if (allowing) {
- ast_codec_pref_append(pref, format);
- ast_codec_pref_setsize(pref, format, framems);
+ ast_codec_pref_append(pref, &format);
+ ast_codec_pref_setsize(pref, &format, framems);
+ } else {
+ ast_codec_pref_remove(pref, &format);
}
- else
- ast_codec_pref_remove(pref, format);
} else if (!allowing) {
memset(pref, 0, sizeof(*pref));
}
@@ -1445,9 +1194,8 @@ static int speex_samples(unsigned char *data, int len)
int ast_codec_get_samples(struct ast_frame *f)
{
int samples = 0;
- char tmp[64];
- switch (f->subclass.codec) {
+ switch (f->subclass.format.id) {
case AST_FORMAT_SPEEX:
samples = speex_samples(f->data.ptr, f->datalen);
break;
@@ -1499,17 +1247,17 @@ int ast_codec_get_samples(struct ast_frame *f)
samples = (int) f->datalen * ((float) 48000 / 8000);
break;
default:
- ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), f->subclass.codec));
+ ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format));
}
return samples;
}
-int ast_codec_get_len(format_t format, int samples)
+int ast_codec_get_len(struct ast_format *format, int samples)
{
int len = 0;
/* XXX Still need speex, and lpc10 XXX */
- switch(format) {
+ switch(format->id) {
case AST_FORMAT_G723_1:
len = (samples / 240) * 20;
break;
@@ -1562,7 +1310,7 @@ int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
short *fdata = f->data.ptr;
short adjust_value = abs(adjustment);
- if ((f->frametype != AST_FRAME_VOICE) || (f->subclass.codec != AST_FORMAT_SLINEAR))
+ if ((f->frametype != AST_FRAME_VOICE) || (f->subclass.format.id != AST_FORMAT_SLINEAR))
return -1;
if (!adjustment)
@@ -1584,10 +1332,10 @@ int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
int count;
short *data1, *data2;
- if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass.codec != AST_FORMAT_SLINEAR))
+ if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass.format.id != AST_FORMAT_SLINEAR))
return -1;
- if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass.codec != AST_FORMAT_SLINEAR))
+ if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass.format.id != AST_FORMAT_SLINEAR))
return -1;
if (f1->samples != f2->samples)
diff --git a/main/image.c b/main/image.c
index 5da07ce06..3aa226653 100644
--- a/main/image.c
+++ b/main/image.c
@@ -96,7 +96,7 @@ static void make_filename(char *buf, int len, const char *filename, const char *
}
}
-struct ast_frame *ast_read_image(const char *filename, const char *preflang, int format)
+struct ast_frame *ast_read_image(const char *filename, const char *preflang, struct ast_format *format)
{
struct ast_imager *i;
char buf[256];
@@ -109,7 +109,8 @@ struct ast_frame *ast_read_image(const char *filename, const char *preflang, int
AST_RWLIST_RDLOCK(&imagers);
AST_RWLIST_TRAVERSE(&imagers, i, list) {
- if (i->format & format) {
+ /* if NULL image format, just pick the first one, otherwise match it. */
+ if (!format || (ast_format_cmp(&i->format, format) == AST_FORMAT_CMP_EQUAL)) {
char *stringp=NULL;
ast_copy_string(tmp, i->exts, sizeof(tmp));
stringp = tmp;
@@ -157,7 +158,7 @@ int ast_send_image(struct ast_channel *chan, const char *filename)
struct ast_frame *f;
int res = -1;
if (chan->tech->send_image) {
- f = ast_read_image(filename, chan->language, -1);
+ f = ast_read_image(filename, chan->language, NULL);
if (f) {
res = chan->tech->send_image(chan, f);
ast_frfree(f);
@@ -189,7 +190,7 @@ static char *handle_core_show_image_formats(struct ast_cli_entry *e, int cmd, st
ast_cli(a->fd, FORMAT, "----", "----------", "-----------", "------");
AST_RWLIST_RDLOCK(&imagers);
AST_RWLIST_TRAVERSE(&imagers, i, list) {
- ast_cli(a->fd, FORMAT2, i->name, i->exts, i->desc, ast_getformatname(i->format));
+ ast_cli(a->fd, FORMAT2, i->name, i->exts, i->desc, ast_getformatname(&i->format));
count_fmt++;
}
AST_RWLIST_UNLOCK(&imagers);
diff --git a/main/indications.c b/main/indications.c
index dcd597ac7..f93239380 100644
--- a/main/indications.c
+++ b/main/indications.c
@@ -116,7 +116,7 @@ struct playtones_state {
int npos;
int oldnpos;
int pos;
- int origwfmt;
+ struct ast_format origwfmt;
struct ast_frame f;
unsigned char offset[AST_FRIENDLY_OFFSET];
short data[4000];
@@ -127,7 +127,7 @@ static void playtones_release(struct ast_channel *chan, void *params)
struct playtones_state *ps = params;
if (chan) {
- ast_set_write_format(chan, ps->origwfmt);
+ ast_set_write_format(chan, &ps->origwfmt);
}
if (ps->items) {
@@ -147,9 +147,9 @@ static void *playtones_alloc(struct ast_channel *chan, void *params)
return NULL;
}
- ps->origwfmt = chan->writeformat;
+ ast_format_copy(&ps->origwfmt, &chan->writeformat);
- if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
+ if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
playtones_release(NULL, ps);
ps = NULL;
@@ -223,7 +223,7 @@ static int playtones_generator(struct ast_channel *chan, void *data, int len, in
}
ps->f.frametype = AST_FRAME_VOICE;
- ps->f.subclass.codec = AST_FORMAT_SLINEAR;
+ ast_format_set(&ps->f.subclass.format, AST_FORMAT_SLINEAR, 0);
ps->f.datalen = len;
ps->f.samples = samples;
ps->f.offset = AST_FRIENDLY_OFFSET;
diff --git a/main/manager.c b/main/manager.c
index 40804bf31..27fa6d8dd 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -3506,7 +3506,7 @@ struct fast_originate_helper {
/*! data can contain a channel name, extension number, username, password, etc. */
char data[512];
int timeout;
- format_t format; /*!< Codecs used for a call */
+ struct ast_format_cap *cap; /*!< Codecs used for a call */
char app[AST_MAX_APP];
char appdata[AST_MAX_EXTENSION];
char cid_name[AST_MAX_EXTENSION];
@@ -3528,12 +3528,12 @@ static void *fast_originate(void *data)
char requested_channel[AST_CHANNEL_NAME];
if (!ast_strlen_zero(in->app)) {
- res = ast_pbx_outgoing_app(in->tech, in->format, in->data, in->timeout, in->app, in->appdata, &reason, 1,
+ res = ast_pbx_outgoing_app(in->tech, in->cap, in->data, in->timeout, in->app, in->appdata, &reason, 1,
S_OR(in->cid_num, NULL),
S_OR(in->cid_name, NULL),
in->vars, in->account, &chan);
} else {
- res = ast_pbx_outgoing_exten(in->tech, in->format, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
+ res = ast_pbx_outgoing_exten(in->tech, in->cap, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
S_OR(in->cid_num, NULL),
S_OR(in->cid_name, NULL),
in->vars, in->account, &chan);
@@ -3565,6 +3565,7 @@ static void *fast_originate(void *data)
if (chan) {
ast_channel_unlock(chan);
}
+ in->cap = ast_format_cap_destroy(in->cap);
ast_free(in);
return NULL;
}
@@ -3822,29 +3823,39 @@ static int action_originate(struct mansession *s, const struct message *m)
int reason = 0;
char tmp[256];
char tmp2[256];
- format_t format = AST_FORMAT_SLINEAR;
-
+ struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+ struct ast_format tmp_fmt;
pthread_t th;
+
+ if (!cap) {
+ astman_send_error(s, m, "Internal Error. Memory allocation failure.");
+ }
+ ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
+
if (ast_strlen_zero(name)) {
astman_send_error(s, m, "Channel not specified");
- return 0;
+ res = 0;
+ goto fast_orig_cleanup;
}
if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
astman_send_error(s, m, "Invalid priority");
- return 0;
+ res = 0;
+ goto fast_orig_cleanup;
}
}
if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
astman_send_error(s, m, "Invalid timeout");
- return 0;
+ res = 0;
+ goto fast_orig_cleanup;
}
ast_copy_string(tmp, name, sizeof(tmp));
tech = tmp;
data = strchr(tmp, '/');
if (!data) {
astman_send_error(s, m, "Invalid channel");
- return 0;
+ res = 0;
+ goto fast_orig_cleanup;
}
*data++ = '\0';
ast_copy_string(tmp2, callerid, sizeof(tmp2));
@@ -3861,8 +3872,8 @@ static int action_originate(struct mansession *s, const struct message *m)
}
}
if (!ast_strlen_zero(codecs)) {
- format = 0;
- ast_parse_allow_disallow(NULL, &format, codecs, 1);
+ ast_format_cap_remove_all(cap);
+ ast_parse_allow_disallow(NULL, cap, codecs, 1);
}
/* Allocate requested channel variables */
vars = astman_get_variables(m);
@@ -3888,10 +3899,12 @@ static int action_originate(struct mansession *s, const struct message *m)
ast_copy_string(fast->context, context, sizeof(fast->context));
ast_copy_string(fast->exten, exten, sizeof(fast->exten));
ast_copy_string(fast->account, account, sizeof(fast->account));
- fast->format = format;
+ fast->cap = cap;
+ cap = NULL; /* transfered originate helper the capabilities structure. It is now responsible for freeing it. */
fast->timeout = to;
fast->priority = pi;
if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
+ ast_format_cap_destroy(fast->cap);
ast_free(fast);
res = -1;
} else {
@@ -3912,18 +3925,20 @@ static int action_originate(struct mansession *s, const struct message *m)
strstr(appdata, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
)) {
astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
- return 0;
+ res = 0;
+ goto fast_orig_cleanup;
}
- res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
+ res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
} else {
if (exten && context && pi) {
- res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
+ res = ast_pbx_outgoing_exten(tech, cap, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
} else {
astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
if (vars) {
ast_variables_destroy(vars);
}
- return 0;
+ res = 0;
+ goto fast_orig_cleanup;
}
}
if (!res) {
@@ -3931,6 +3946,9 @@ static int action_originate(struct mansession *s, const struct message *m)
} else {
astman_send_error(s, m, "Originate failed");
}
+
+fast_orig_cleanup:
+ ast_format_cap_destroy(cap);
return 0;
}
diff --git a/main/pbx.c b/main/pbx.c
index bceceb00f..1d8324e6e 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -8503,7 +8503,7 @@ static int ast_pbx_outgoing_cdr_failed(void)
return 0; /* success */
}
-int ast_pbx_outgoing_exten(const char *type, format_t format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
+int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
{
struct ast_channel *chan;
struct async_stat *as;
@@ -8520,7 +8520,7 @@ int ast_pbx_outgoing_exten(const char *type, format_t format, void *data, int ti
oh.vars = vars;
oh.parent_channel = NULL;
- chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
+ chan = __ast_request_and_dial(type, cap, NULL, data, timeout, reason, cid_num, cid_name, &oh);
if (channel) {
*channel = chan;
if (chan)
@@ -8610,7 +8610,7 @@ int ast_pbx_outgoing_exten(const char *type, format_t format, void *data, int ti
res = -1;
goto outgoing_exten_cleanup;
}
- chan = ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name);
+ chan = ast_request_and_dial(type, cap, NULL, data, timeout, reason, cid_num, cid_name);
if (channel) {
*channel = chan;
if (chan)
@@ -8669,7 +8669,7 @@ static void *ast_pbx_run_app(void *data)
return NULL;
}
-int ast_pbx_outgoing_app(const char *type, format_t format, void *data, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
+int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, void *data, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
{
struct ast_channel *chan;
struct app_tmp *tmp;
@@ -8687,7 +8687,7 @@ int ast_pbx_outgoing_app(const char *type, format_t format, void *data, int time
goto outgoing_app_cleanup;
}
if (synchronous) {
- chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
+ chan = __ast_request_and_dial(type, cap, NULL, data, timeout, reason, cid_num, cid_name, &oh);
if (chan) {
ast_set_variables(chan, vars);
if (account)
@@ -8752,7 +8752,7 @@ int ast_pbx_outgoing_app(const char *type, format_t format, void *data, int time
res = -1;
goto outgoing_app_cleanup;
}
- chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
+ chan = __ast_request_and_dial(type, cap, NULL, data, timeout, reason, cid_num, cid_name, &oh);
if (!chan) {
ast_free(as);
res = -1;
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 4a4dbf595..738b58fae 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -89,43 +89,43 @@ static const struct ast_rtp_mime_type {
char *subtype;
unsigned int sample_rate;
} ast_rtp_mime_types[] = {
- {{1, AST_FORMAT_G723_1}, "audio", "G723", 8000},
- {{1, AST_FORMAT_GSM}, "audio", "GSM", 8000},
- {{1, AST_FORMAT_ULAW}, "audio", "PCMU", 8000},
- {{1, AST_FORMAT_ULAW}, "audio", "G711U", 8000},
- {{1, AST_FORMAT_ALAW}, "audio", "PCMA", 8000},
- {{1, AST_FORMAT_ALAW}, "audio", "G711A", 8000},
- {{1, AST_FORMAT_G726}, "audio", "G726-32", 8000},
- {{1, AST_FORMAT_ADPCM}, "audio", "DVI4", 8000},
- {{1, AST_FORMAT_SLINEAR}, "audio", "L16", 8000},
- {{1, AST_FORMAT_SLINEAR16}, "audio", "L16", 16000},
- {{1, AST_FORMAT_LPC10}, "audio", "LPC", 8000},
- {{1, AST_FORMAT_G729A}, "audio", "G729", 8000},
- {{1, AST_FORMAT_G729A}, "audio", "G729A", 8000},
- {{1, AST_FORMAT_G729A}, "audio", "G.729", 8000},
- {{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000},
- {{1, AST_FORMAT_SPEEX16}, "audio", "speex", 16000},
- {{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000},
+ {{1, {.id = AST_FORMAT_G723_1}, 0}, "audio", "G723", 8000},
+ {{1, {.id = AST_FORMAT_GSM}, 0}, "audio", "GSM", 8000},
+ {{1, {.id = AST_FORMAT_ULAW}, 0}, "audio", "PCMU", 8000},
+ {{1, {.id = AST_FORMAT_ULAW}, 0}, "audio", "G711U", 8000},
+ {{1, {.id = AST_FORMAT_ALAW}, 0}, "audio", "PCMA", 8000},
+ {{1, {.id = AST_FORMAT_ALAW}, 0}, "audio", "G711A", 8000},
+ {{1, {.id = AST_FORMAT_G726}, 0}, "audio", "G726-32", 8000},
+ {{1, {.id = AST_FORMAT_ADPCM}, 0}, "audio", "DVI4", 8000},
+ {{1, {.id = AST_FORMAT_SLINEAR}, 0}, "audio", "L16", 8000},
+ {{1, {.id = AST_FORMAT_SLINEAR16}, 0}, "audio", "L16", 16000},
+ {{1, {.id = AST_FORMAT_LPC10}, 0}, "audio", "LPC", 8000},
+ {{1, {.id = AST_FORMAT_G729A}, 0}, "audio", "G729", 8000},
+ {{1, {.id = AST_FORMAT_G729A}, 0}, "audio", "G729A", 8000},
+ {{1, {.id = AST_FORMAT_G729A}, 0}, "audio", "G.729", 8000},
+ {{1, {.id = AST_FORMAT_SPEEX}, 0}, "audio", "speex", 8000},
+ {{1, {.id = AST_FORMAT_SPEEX16}, 0}, "audio", "speex", 16000},
+ {{1, {.id = AST_FORMAT_ILBC}, 0}, "audio", "iLBC", 8000},
/* this is the sample rate listed in the RTP profile for the G.722
codec, *NOT* the actual sample rate of the media stream
*/
- {{1, AST_FORMAT_G722}, "audio", "G722", 8000},
- {{1, AST_FORMAT_G726_AAL2}, "audio", "AAL2-G726-32", 8000},
- {{0, AST_RTP_DTMF}, "audio", "telephone-event", 8000},
- {{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event", 8000},
- {{0, AST_RTP_CN}, "audio", "CN", 8000},
- {{1, AST_FORMAT_JPEG}, "video", "JPEG", 90000},
- {{1, AST_FORMAT_PNG}, "video", "PNG", 90000},
- {{1, AST_FORMAT_H261}, "video", "H261", 90000},
- {{1, AST_FORMAT_H263}, "video", "H263", 90000},
- {{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998", 90000},
- {{1, AST_FORMAT_H264}, "video", "H264", 90000},
- {{1, AST_FORMAT_MP4_VIDEO}, "video", "MP4V-ES", 90000},
- {{1, AST_FORMAT_T140RED}, "text", "RED", 1000},
- {{1, AST_FORMAT_T140}, "text", "T140", 1000},
- {{1, AST_FORMAT_SIREN7}, "audio", "G7221", 16000},
- {{1, AST_FORMAT_SIREN14}, "audio", "G7221", 32000},
- {{1, AST_FORMAT_G719}, "audio", "G719", 48000},
+ {{1, {.id = AST_FORMAT_G722}, 0}, "audio", "G722", 8000},
+ {{1, {.id = AST_FORMAT_G726_AAL2}, 0}, "audio", "AAL2-G726-32", 8000},
+ {{0, {.id = 0}, AST_RTP_DTMF}, "audio", "telephone-event", 8000},
+ {{0, {.id = 0}, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event", 8000},
+ {{0, {.id = 0}, AST_RTP_CN}, "audio", "CN", 8000},
+ {{1, {.id = AST_FORMAT_JPEG}, 0}, "video", "JPEG", 90000},
+ {{1, {.id = AST_FORMAT_PNG}, 0}, "video", "PNG", 90000},
+ {{1, {.id = AST_FORMAT_H261}, 0}, "video", "H261", 90000},
+ {{1, {.id = AST_FORMAT_H263}, 0}, "video", "H263", 90000},
+ {{1, {.id = AST_FORMAT_H263_PLUS}, 0}, "video", "h263-1998", 90000},
+ {{1, {.id = AST_FORMAT_H264}, 0}, "video", "H264", 90000},
+ {{1, {.id = AST_FORMAT_MP4_VIDEO}, 0}, "video", "MP4V-ES", 90000},
+ {{1, {.id = AST_FORMAT_T140RED}, 0}, "text", "RED", 1000},
+ {{1, {.id = AST_FORMAT_T140}, 0}, "text", "T140", 1000},
+ {{1, {.id = AST_FORMAT_SIREN7}, 0}, "audio", "G7221", 16000},
+ {{1, {.id = AST_FORMAT_SIREN14}, 0}, "audio", "G7221", 32000},
+ {{1, {.id = AST_FORMAT_G719}, 0}, "audio", "G719", 48000},
};
/*!
@@ -139,44 +139,44 @@ static const struct ast_rtp_mime_type {
* assigned values
*/
static const struct ast_rtp_payload_type static_RTP_PT[AST_RTP_MAX_PT] = {
- [0] = {1, AST_FORMAT_ULAW},
+ [0] = {1, {.id = AST_FORMAT_ULAW}, 0},
#ifdef USE_DEPRECATED_G726
- [2] = {1, AST_FORMAT_G726}, /* Technically this is G.721, but if Cisco can do it, so can we... */
+ [2] = {1, {.id = AST_FORMAT_G726}, 0},/* Technically this is G.721, but if Cisco can do it, so can we... */
#endif
- [3] = {1, AST_FORMAT_GSM},
- [4] = {1, AST_FORMAT_G723_1},
- [5] = {1, AST_FORMAT_ADPCM}, /* 8 kHz */
- [6] = {1, AST_FORMAT_ADPCM}, /* 16 kHz */
- [7] = {1, AST_FORMAT_LPC10},
- [8] = {1, AST_FORMAT_ALAW},
- [9] = {1, AST_FORMAT_G722},
- [10] = {1, AST_FORMAT_SLINEAR}, /* 2 channels */
- [11] = {1, AST_FORMAT_SLINEAR}, /* 1 channel */
- [13] = {0, AST_RTP_CN},
- [16] = {1, AST_FORMAT_ADPCM}, /* 11.025 kHz */
- [17] = {1, AST_FORMAT_ADPCM}, /* 22.050 kHz */
- [18] = {1, AST_FORMAT_G729A},
- [19] = {0, AST_RTP_CN}, /* Also used for CN */
- [26] = {1, AST_FORMAT_JPEG},
- [31] = {1, AST_FORMAT_H261},
- [34] = {1, AST_FORMAT_H263},
- [97] = {1, AST_FORMAT_ILBC},
- [98] = {1, AST_FORMAT_H263_PLUS},
- [99] = {1, AST_FORMAT_H264},
- [101] = {0, AST_RTP_DTMF},
- [102] = {1, AST_FORMAT_SIREN7},
- [103] = {1, AST_FORMAT_H263_PLUS},
- [104] = {1, AST_FORMAT_MP4_VIDEO},
- [105] = {1, AST_FORMAT_T140RED}, /* Real time text chat (with redundancy encoding) */
- [106] = {1, AST_FORMAT_T140}, /* Real time text chat */
- [110] = {1, AST_FORMAT_SPEEX},
- [111] = {1, AST_FORMAT_G726},
- [112] = {1, AST_FORMAT_G726_AAL2},
- [115] = {1, AST_FORMAT_SIREN14},
- [116] = {1, AST_FORMAT_G719},
- [117] = {1, AST_FORMAT_SPEEX16},
- [118] = {1, AST_FORMAT_SLINEAR16}, /* 16 Khz signed linear */
- [121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
+ [3] = {1, {.id = AST_FORMAT_GSM}, 0},
+ [4] = {1, {.id = AST_FORMAT_G723_1}, 0},
+ [5] = {1, {.id = AST_FORMAT_ADPCM}, 0},/* 8 kHz */
+ [6] = {1, {.id = AST_FORMAT_ADPCM}, 0}, /* 16 kHz */
+ [7] = {1, {.id = AST_FORMAT_LPC10}, 0},
+ [8] = {1, {.id = AST_FORMAT_ALAW}, 0},
+ [9] = {1, {.id = AST_FORMAT_G722}, 0},
+ [10] = {1, {.id = AST_FORMAT_SLINEAR}, 0}, /* 2 channels */
+ [11] = {1, {.id = AST_FORMAT_SLINEAR}, 0}, /* 1 channel */
+ [13] = {0, {.id = 0}, AST_RTP_CN},
+ [16] = {1, {.id = AST_FORMAT_ADPCM}, 0}, /* 11.025 kHz */
+ [17] = {1, {.id = AST_FORMAT_ADPCM}, 0}, /* 22.050 kHz */
+ [18] = {1, {.id = AST_FORMAT_G729A}, 0},
+ [19] = {0, {.id = 0}, AST_RTP_CN}, /* Also used for CN */
+ [26] = {1, {.id = AST_FORMAT_JPEG}, 0},
+ [31] = {1, {.id = AST_FORMAT_H261}, 0},
+ [34] = {1, {.id = AST_FORMAT_H263}, 0},
+ [97] = {1, {.id = AST_FORMAT_ILBC}, 0},
+ [98] = {1, {.id = AST_FORMAT_H263_PLUS}, 0},
+ [99] = {1, {.id = AST_FORMAT_H264}, 0},
+ [101] = {0, {.id = 0}, AST_RTP_DTMF},
+ [102] = {1, {.id = AST_FORMAT_SIREN7}, 0},
+ [103] = {1, {.id = AST_FORMAT_H263_PLUS}, 0},
+ [104] = {1, {.id = AST_FORMAT_MP4_VIDEO}, 0},
+ [105] = {1, {.id = AST_FORMAT_T140RED}, 0}, /* Real time text chat (with redundancy encoding) */
+ [106] = {1, {.id = AST_FORMAT_T140}, 0}, /* Real time text chat */
+ [110] = {1, {.id = AST_FORMAT_SPEEX}, 0},
+ [111] = {1, {.id = AST_FORMAT_G726}, 0},
+ [112] = {1, {.id = AST_FORMAT_G726_AAL2}, 0},
+ [115] = {1, {.id = AST_FORMAT_SIREN14}, 0},
+ [116] = {1, {.id = AST_FORMAT_G719}, 0},
+ [117] = {1, {.id = AST_FORMAT_SPEEX16}, 0},
+ [118] = {1, {.id = AST_FORMAT_SLINEAR16}, 0}, /* 16 Khz signed linear */
+ [121] = {0, {.id = 0}, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
};
int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module)
@@ -485,9 +485,10 @@ void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp
for (i = 0; i < AST_RTP_MAX_PT; i++) {
codecs->payloads[i].asterisk_format = 0;
- codecs->payloads[i].code = 0;
+ codecs->payloads[i].rtp_code = 0;
+ ast_format_clear(&codecs->payloads[i].format);
if (instance && instance->engine && instance->engine->payload_set) {
- instance->engine->payload_set(instance, i, 0, 0);
+ instance->engine->payload_set(instance, i, 0, NULL, 0);
}
}
}
@@ -497,11 +498,13 @@ void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_r
int i;
for (i = 0; i < AST_RTP_MAX_PT; i++) {
- if (static_RTP_PT[i].code) {
+ if (static_RTP_PT[i].rtp_code || static_RTP_PT[i].asterisk_format) {
+
codecs->payloads[i].asterisk_format = static_RTP_PT[i].asterisk_format;
- codecs->payloads[i].code = static_RTP_PT[i].code;
+ codecs->payloads[i].rtp_code = static_RTP_PT[i].rtp_code;
+ ast_format_copy(&codecs->payloads[i].format, &static_RTP_PT[i].format);
if (instance && instance->engine && instance->engine->payload_set) {
- instance->engine->payload_set(instance, i, codecs->payloads[i].asterisk_format, codecs->payloads[i].code);
+ instance->engine->payload_set(instance, i, codecs->payloads[i].asterisk_format, &codecs->payloads[i].format, codecs->payloads[i].rtp_code);
}
}
}
@@ -512,12 +515,13 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod
int i;
for (i = 0; i < AST_RTP_MAX_PT; i++) {
- if (src->payloads[i].code) {
+ if (src->payloads[i].rtp_code || src->payloads[i].asterisk_format) {
ast_debug(2, "Copying payload %d from %p to %p\n", i, src, dest);
dest->payloads[i].asterisk_format = src->payloads[i].asterisk_format;
- dest->payloads[i].code = src->payloads[i].code;
+ dest->payloads[i].rtp_code = src->payloads[i].rtp_code;
+ ast_format_copy(&dest->payloads[i].format, &src->payloads[i].format);
if (instance && instance->engine && instance->engine->payload_set) {
- instance->engine->payload_set(instance, i, dest->payloads[i].asterisk_format, dest->payloads[i].code);
+ instance->engine->payload_set(instance, i, dest->payloads[i].asterisk_format, &dest->payloads[i].format, dest->payloads[i].rtp_code);
}
}
}
@@ -525,17 +529,18 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod
void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
{
- if (payload < 0 || payload >= AST_RTP_MAX_PT || !static_RTP_PT[payload].code) {
+ if (payload < 0 || payload >= AST_RTP_MAX_PT || (!static_RTP_PT[payload].rtp_code && !static_RTP_PT[payload].asterisk_format)) {
return;
}
codecs->payloads[payload].asterisk_format = static_RTP_PT[payload].asterisk_format;
- codecs->payloads[payload].code = static_RTP_PT[payload].code;
+ codecs->payloads[payload].rtp_code = static_RTP_PT[payload].rtp_code;
+ ast_format_copy(&codecs->payloads[payload].format, &static_RTP_PT[payload].format);
ast_debug(1, "Setting payload %d based on m type on %p\n", payload, codecs);
if (instance && instance->engine && instance->engine->payload_set) {
- instance->engine->payload_set(instance, payload, codecs->payloads[payload].asterisk_format, codecs->payloads[payload].code);
+ instance->engine->payload_set(instance, payload, codecs->payloads[payload].asterisk_format, &codecs->payloads[payload].format, codecs->payloads[payload].rtp_code);
}
}
@@ -572,14 +577,12 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
found = 1;
codecs->payloads[pt] = t->payload_type;
- if ((t->payload_type.code == AST_FORMAT_G726) &&
- t->payload_type.asterisk_format &&
- (options & AST_RTP_OPT_G726_NONSTANDARD)) {
- codecs->payloads[pt].code = AST_FORMAT_G726_AAL2;
+ if ((t->payload_type.format.id == AST_FORMAT_G726) && t->payload_type.asterisk_format && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
+ ast_format_set(&codecs->payloads[pt].format, AST_FORMAT_G726_AAL2, 0);
}
if (instance && instance->engine && instance->engine->payload_set) {
- instance->engine->payload_set(instance, pt, codecs->payloads[i].asterisk_format, codecs->payloads[i].code);
+ instance->engine->payload_set(instance, pt, codecs->payloads[i].asterisk_format, &codecs->payloads[i].format, codecs->payloads[i].rtp_code);
}
break;
@@ -602,10 +605,11 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp
ast_debug(2, "Unsetting payload %d on %p\n", payload, codecs);
codecs->payloads[payload].asterisk_format = 0;
- codecs->payloads[payload].code = 0;
+ codecs->payloads[payload].rtp_code = 0;
+ ast_format_clear(&codecs->payloads[payload].format);
if (instance && instance->engine && instance->engine->payload_set) {
- instance->engine->payload_set(instance, payload, 0, 0);
+ instance->engine->payload_set(instance, payload, 0, NULL, 0);
}
}
@@ -618,45 +622,55 @@ struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs
}
result.asterisk_format = codecs->payloads[payload].asterisk_format;
- result.code = codecs->payloads[payload].code;
+ result.rtp_code = codecs->payloads[payload].rtp_code;
+ ast_format_copy(&result.format, &codecs->payloads[payload].format);
- if (!result.code) {
+ if (!result.rtp_code && !result.asterisk_format) {
result = static_RTP_PT[payload];
}
return result;
}
-void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, format_t *astformats, int *nonastformats)
+void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_format_cap *astformats, int *nonastformats)
{
int i;
- *astformats = *nonastformats = 0;
+ ast_format_cap_remove_all(astformats);
+ *nonastformats = 0;
for (i = 0; i < AST_RTP_MAX_PT; i++) {
- if (codecs->payloads[i].code) {
+ if (codecs->payloads[i].rtp_code || codecs->payloads[i].asterisk_format) {
ast_debug(1, "Incorporating payload %d on %p\n", i, codecs);
}
if (codecs->payloads[i].asterisk_format) {
- *astformats |= codecs->payloads[i].code;
+ ast_format_cap_add(astformats, &codecs->payloads[i].format);
} else {
- *nonastformats |= codecs->payloads[i].code;
+ *nonastformats |= codecs->payloads[i].rtp_code;
}
}
}
-int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, const int asterisk_format, const format_t code)
+int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
{
int i;
for (i = 0; i < AST_RTP_MAX_PT; i++) {
- if (codecs->payloads[i].asterisk_format == asterisk_format && codecs->payloads[i].code == code) {
+ if (codecs->payloads[i].asterisk_format && asterisk_format && format &&
+ (ast_format_cmp(format, &codecs->payloads[i].format) != AST_FORMAT_CMP_NOT_EQUAL)) {
+ return i;
+ } else if (!codecs->payloads[i].asterisk_format && !asterisk_format &&
+ (codecs->payloads[i].rtp_code == code)) {
return i;
}
}
for (i = 0; i < AST_RTP_MAX_PT; i++) {
- if (static_RTP_PT[i].asterisk_format == asterisk_format && static_RTP_PT[i].code == code) {
+ if (static_RTP_PT[i].asterisk_format && asterisk_format && format &&
+ (ast_format_cmp(format, &static_RTP_PT[i].format) != AST_FORMAT_CMP_NOT_EQUAL)) {
+ return i;
+ } else if (!static_RTP_PT[i].asterisk_format && !asterisk_format &&
+ (static_RTP_PT[i].rtp_code == code)) {
return i;
}
}
@@ -664,29 +678,38 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, const int asteris
return -1;
}
-const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, const format_t code, enum ast_rtp_options options)
+const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_format *format, int code, enum ast_rtp_options options)
{
int i;
for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); i++) {
- if (ast_rtp_mime_types[i].payload_type.code == code && ast_rtp_mime_types[i].payload_type.asterisk_format == asterisk_format) {
- if (asterisk_format && (code == AST_FORMAT_G726_AAL2) && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
+ if (ast_rtp_mime_types[i].payload_type.asterisk_format && asterisk_format && format &&
+ (ast_format_cmp(format, &ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) {
+ if ((format->id == AST_FORMAT_G726_AAL2) && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
return "G726-32";
} else {
return ast_rtp_mime_types[i].subtype;
}
+ } else if (!ast_rtp_mime_types[i].payload_type.asterisk_format && !asterisk_format &&
+ ast_rtp_mime_types[i].payload_type.rtp_code == code) {
+
+ return ast_rtp_mime_types[i].subtype;
}
}
return "";
}
-unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, format_t code)
+unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format *format, int code)
{
unsigned int i;
for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); ++i) {
- if ((ast_rtp_mime_types[i].payload_type.code == code) && (ast_rtp_mime_types[i].payload_type.asterisk_format == asterisk_format)) {
+ if (ast_rtp_mime_types[i].payload_type.asterisk_format && asterisk_format && format &&
+ (ast_format_cmp(format, &ast_rtp_mime_types[i].payload_type.format) != AST_FORMAT_CMP_NOT_EQUAL)) {
+ return ast_rtp_mime_types[i].sample_rate;
+ } else if (!ast_rtp_mime_types[i].payload_type.asterisk_format && !asterisk_format &&
+ ast_rtp_mime_types[i].payload_type.rtp_code == code) {
return ast_rtp_mime_types[i].sample_rate;
}
}
@@ -694,23 +717,35 @@ unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, format_t code)
return 0;
}
-char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, const format_t capability, const int asterisk_format, enum ast_rtp_options options)
+char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, struct ast_format_cap *ast_format_capability, int rtp_capability, const int asterisk_format, enum ast_rtp_options options)
{
- format_t format;
int found = 0;
-
+ const char *name;
if (!buf) {
return NULL;
}
- ast_str_append(&buf, 0, "0x%llx (", (unsigned long long) capability);
- for (format = 1; format < AST_RTP_MAX; format <<= 1) {
- if (capability & format) {
- const char *name = ast_rtp_lookup_mime_subtype2(asterisk_format, format, options);
+ if (asterisk_format) {
+ struct ast_format tmp_fmt;
+ ast_format_cap_iter_start(ast_format_capability);
+ while (!ast_format_cap_iter_next(ast_format_capability, &tmp_fmt)) {
+ name = ast_rtp_lookup_mime_subtype2(asterisk_format, &tmp_fmt, 0, options);
ast_str_append(&buf, 0, "%s|", name);
found = 1;
}
+ ast_format_cap_iter_end(ast_format_capability);
+
+ } else {
+ int x;
+ ast_str_append(&buf, 0, "0x%x (", (unsigned int) rtp_capability);
+ for (x = 1; x < AST_RTP_MAX; x <<= 1) {
+ if (rtp_capability & x) {
+ name = ast_rtp_lookup_mime_subtype2(asterisk_format, NULL, x, options);
+ ast_str_append(&buf, 0, "%s|", name);
+ found = 1;
+ }
+ }
}
ast_str_append(&buf, 0, "%s", found ? ")" : "nothing)");
@@ -842,7 +877,8 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a
cs[2] = NULL;
for (;;) {
/* If the underlying formats have changed force this bridge to break */
- if ((c0->rawreadformat != c1->rawwriteformat) || (c1->rawreadformat != c0->rawwriteformat)) {
+ if ((ast_format_cmp(&c0->rawreadformat, &c1->rawwriteformat) == AST_FORMAT_CMP_NOT_EQUAL) ||
+ (ast_format_cmp(&c1->rawreadformat, &c0->rawwriteformat) == AST_FORMAT_CMP_NOT_EQUAL)) {
ast_debug(1, "rtp-engine-local-bridge: Oooh, formats changed, backing out\n");
res = AST_BRIDGE_FAILED_NOWARN;
break;
@@ -969,20 +1005,40 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a
return res;
}
-static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1,
- struct ast_rtp_instance *vinstance0, struct ast_rtp_instance *vinstance1, struct ast_rtp_instance *tinstance0,
- struct ast_rtp_instance *tinstance1, struct ast_rtp_glue *glue0, struct ast_rtp_glue *glue1, format_t codec0, format_t codec1, int timeoutms,
- int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
+static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0,
+ struct ast_channel *c1,
+ struct ast_rtp_instance *instance0,
+ struct ast_rtp_instance *instance1,
+ struct ast_rtp_instance *vinstance0,
+ struct ast_rtp_instance *vinstance1,
+ struct ast_rtp_instance *tinstance0,
+ struct ast_rtp_instance *tinstance1,
+ struct ast_rtp_glue *glue0,
+ struct ast_rtp_glue *glue1,
+ struct ast_format_cap *cap0,
+ struct ast_format_cap *cap1,
+ int timeoutms,
+ int flags,
+ struct ast_frame **fo,
+ struct ast_channel **rc,
+ void *pvt0,
+ void *pvt1)
{
enum ast_bridge_result res = AST_BRIDGE_FAILED;
struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
- format_t oldcodec0 = codec0, oldcodec1 = codec1;
+ struct ast_format_cap *oldcap0 = ast_format_cap_dup(cap0);
+ struct ast_format_cap *oldcap1 = ast_format_cap_dup(cap1);
struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}};
struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}};
struct ast_frame *fr = NULL;
+ if (!oldcap0 || !oldcap1) {
+ ast_channel_unlock(c0);
+ ast_channel_unlock(c1);
+ goto remote_bridge_cleanup;
+ }
/* Test the first channel */
- if (!(glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0))) {
+ if (!(glue0->update_peer(c0, instance1, vinstance1, tinstance1, cap1, 0))) {
ast_rtp_instance_get_remote_address(instance1, &ac1);
if (vinstance1) {
ast_rtp_instance_get_remote_address(vinstance1, &vac1);
@@ -995,7 +1051,7 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
}
/* Test the second channel */
- if (!(glue1->update_peer(c1, instance0, vinstance0, tinstance0, codec0, 0))) {
+ if (!(glue1->update_peer(c1, instance0, vinstance0, tinstance0, cap0, 0))) {
ast_rtp_instance_get_remote_address(instance0, &ac0);
if (vinstance0) {
ast_rtp_instance_get_remote_address(instance0, &vac0);
@@ -1039,7 +1095,8 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
ast_rtp_instance_get_remote_address(tinstance1, &tt1);
}
if (glue1->get_codec) {
- codec1 = glue1->get_codec(c1);
+ ast_format_cap_remove_all(cap1);
+ glue1->get_codec(c1, cap1);
}
ast_rtp_instance_get_remote_address(instance0, &t0);
@@ -1050,63 +1107,66 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
ast_rtp_instance_get_remote_address(tinstance0, &tt0);
}
if (glue0->get_codec) {
- codec0 = glue0->get_codec(c0);
+ ast_format_cap_remove_all(cap0);
+ glue0->get_codec(c0, cap0);
}
if ((ast_sockaddr_cmp(&t1, &ac1)) ||
(vinstance1 && ast_sockaddr_cmp(&vt1, &vac1)) ||
(tinstance1 && ast_sockaddr_cmp(&tt1, &tac1)) ||
- (codec1 != oldcodec1)) {
+ (!ast_format_cap_identical(cap1, oldcap1))) {
+ char tmp_buf[512] = { 0, };
ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n",
c1->name, ast_sockaddr_stringify(&t1),
- ast_getformatname(codec1));
+ ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1));
ast_debug(1, "Oooh, '%s' changed end vaddress to %s (format %s)\n",
c1->name, ast_sockaddr_stringify(&vt1),
- ast_getformatname(codec1));
+ ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1));
ast_debug(1, "Oooh, '%s' changed end taddress to %s (format %s)\n",
c1->name, ast_sockaddr_stringify(&tt1),
- ast_getformatname(codec1));
+ ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1));
ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
c1->name, ast_sockaddr_stringify(&ac1),
- ast_getformatname(oldcodec1));
+ ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1));
ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
c1->name, ast_sockaddr_stringify(&vac1),
- ast_getformatname(oldcodec1));
+ ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1));
ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
c1->name, ast_sockaddr_stringify(&tac1),
- ast_getformatname(oldcodec1));
+ ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1));
if (glue0->update_peer(c0,
ast_sockaddr_isnull(&t1) ? NULL : instance1,
ast_sockaddr_isnull(&vt1) ? NULL : vinstance1,
ast_sockaddr_isnull(&tt1) ? NULL : tinstance1,
- codec1, 0)) {
+ cap1, 0)) {
ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
}
ast_sockaddr_copy(&ac1, &t1);
ast_sockaddr_copy(&vac1, &vt1);
ast_sockaddr_copy(&tac1, &tt1);
- oldcodec1 = codec1;
+ ast_format_cap_copy(oldcap1, cap1);
}
if ((ast_sockaddr_cmp(&t0, &ac0)) ||
(vinstance0 && ast_sockaddr_cmp(&vt0, &vac0)) ||
(tinstance0 && ast_sockaddr_cmp(&tt0, &tac0)) ||
- (codec0 != oldcodec0)) {
+ (!ast_format_cap_identical(cap0, oldcap0))) {
+ char tmp_buf[512] = { 0, };
ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n",
c0->name, ast_sockaddr_stringify(&t0),
- ast_getformatname(codec0));
+ ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap0));
ast_debug(1, "Oooh, '%s' was %s/(format %s)\n",
c0->name, ast_sockaddr_stringify(&ac0),
- ast_getformatname(oldcodec0));
+ ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap0));
if (glue1->update_peer(c1, t0.len ? instance0 : NULL,
vt0.len ? vinstance0 : NULL,
tt0.len ? tinstance0 : NULL,
- codec0, 0)) {
+ cap0, 0)) {
ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
}
ast_sockaddr_copy(&ac0, &t0);
ast_sockaddr_copy(&vac0, &vt0);
ast_sockaddr_copy(&tac0, &tt0);
- oldcodec0 = codec0;
+ ast_format_cap_copy(oldcap0, cap0);
}
/* Wait for frame to come in on the channels */
@@ -1148,9 +1208,9 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
} else if (fr->subclass.integer == AST_CONTROL_UNHOLD) {
/* If they went off hold they should go back to being direct */
if (who == c0) {
- glue1->update_peer(c1, instance0, vinstance0, tinstance0, codec0, 0);
+ glue1->update_peer(c1, instance0, vinstance0, tinstance0, cap0, 0);
} else {
- glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0);
+ glue0->update_peer(c0, instance1, vinstance1, tinstance1, cap1, 0);
}
}
/* Update local address information */
@@ -1160,10 +1220,17 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
ast_sockaddr_copy(&ac1, &t1);
/* Update codec information */
if (glue0->get_codec && c0->tech_pvt) {
- oldcodec0 = codec0 = glue0->get_codec(c0);
+ ast_format_cap_remove_all(cap0);
+ ast_format_cap_remove_all(oldcap0);
+ glue0->get_codec(c0, cap0);
+ ast_format_cap_append(oldcap0, cap0);
+
}
if (glue1->get_codec && c1->tech_pvt) {
- oldcodec1 = codec1 = glue1->get_codec(c1);
+ ast_format_cap_remove_all(cap1);
+ ast_format_cap_remove_all(oldcap1);
+ glue0->get_codec(c1, cap1);
+ ast_format_cap_append(oldcap1, cap1);
}
ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
ast_frfree(fr);
@@ -1181,7 +1248,8 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
*fo = fr;
*rc = who;
ast_debug(1, "Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass.integer, who->name);
- return AST_BRIDGE_COMPLETE;
+ res = AST_BRIDGE_COMPLETE;
+ goto remote_bridge_cleanup;
}
} else {
if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
@@ -1214,6 +1282,10 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
ast_poll_channel_del(c0, c1);
+remote_bridge_cleanup:
+ ast_format_cap_destroy(oldcap0);
+ ast_format_cap_destroy(oldcap1);
+
return res;
}
@@ -1238,9 +1310,15 @@ enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct as
enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID, text_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID, text_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
enum ast_bridge_result res = AST_BRIDGE_FAILED;
- format_t codec0 = 0, codec1 = 0;
+ struct ast_format_cap *cap0 = ast_format_cap_alloc_nolock();
+ struct ast_format_cap *cap1 = ast_format_cap_alloc_nolock();
int unlock_chans = 1;
+ if (!cap0 || !cap1) {
+ unlock_chans = 0;
+ goto done;
+ }
+
/* Lock both channels so we can look for the glue that binds them together */
ast_channel_lock(c0);
while (ast_channel_trylock(c1)) {
@@ -1311,10 +1389,18 @@ enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct as
}
/* Make sure that codecs match */
- codec0 = glue0->get_codec ? glue0->get_codec(c0) : 0;
- codec1 = glue1->get_codec ? glue1->get_codec(c1) : 0;
- if (codec0 && codec1 && !(codec0 & codec1)) {
- ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n", ast_getformatname(codec0), ast_getformatname(codec1));
+ if (glue0->get_codec){
+ glue0->get_codec(c0, cap0);
+ }
+ if (glue1->get_codec) {
+ glue1->get_codec(c1, cap1);
+ }
+ if (!ast_format_cap_is_empty(cap0) && !ast_format_cap_is_empty(cap1) && !ast_format_cap_has_joint(cap0, cap1)) {
+ char tmp0[256] = { 0, };
+ char tmp1[256] = { 0, };
+ ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
+ ast_getformatname_multiple(tmp0, sizeof(tmp0), cap0),
+ ast_getformatname_multiple(tmp1, sizeof(tmp1), cap1));
res = AST_BRIDGE_FAILED_NOWARN;
goto done;
}
@@ -1331,7 +1417,7 @@ enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct as
} else {
ast_verbose(VERBOSE_PREFIX_3 "Remotely bridging %s and %s\n", c0->name, c1->name);
res = remote_bridge_loop(c0, c1, instance0, instance1, vinstance0, vinstance1,
- tinstance0, tinstance1, glue0, glue1, codec0, codec1, timeoutms, flags,
+ tinstance0, tinstance1, glue0, glue1, cap0, cap1, timeoutms, flags,
fo, rc, c0->tech_pvt, c1->tech_pvt);
}
@@ -1347,6 +1433,8 @@ done:
ast_channel_unlock(c0);
ast_channel_unlock(c1);
}
+ ast_format_cap_destroy(cap1);
+ ast_format_cap_destroy(cap0);
unref_instance_cond(&instance0);
unref_instance_cond(&instance1);
@@ -1371,7 +1459,8 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c0, struc
struct ast_rtp_glue *glue0, *glue1;
enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID, text_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID, text_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
- format_t codec0 = 0, codec1 = 0;
+ struct ast_format_cap *cap0 = ast_format_cap_alloc_nolock();
+ struct ast_format_cap *cap1 = ast_format_cap_alloc_nolock();
int res = 0;
/* Lock both channels so we can look for the glue that binds them together */
@@ -1382,6 +1471,10 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c0, struc
ast_channel_lock(c0);
}
+ if (!cap1 || !cap0) {
+ goto done;
+ }
+
/* Grab glue that binds each channel to something using the RTP engine */
if (!(glue0 = ast_rtp_instance_get_glue(c0->tech->type)) || !(glue1 = ast_rtp_instance_get_glue(c1->tech->type))) {
ast_debug(1, "Can't find native functions for channel '%s'\n", glue0 ? c1->name : c0->name);
@@ -1404,10 +1497,10 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c0, struc
audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
}
if (audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE) && glue0->get_codec) {
- codec0 = glue0->get_codec(c0);
+ glue0->get_codec(c0, cap0);
}
if (audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) && glue1->get_codec) {
- codec1 = glue1->get_codec(c1);
+ glue1->get_codec(c1, cap1);
}
/* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
@@ -1416,7 +1509,7 @@ void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c0, struc
}
/* Make sure we have matching codecs */
- if (!(codec0 & codec1)) {
+ if (!ast_format_cap_has_joint(cap0, cap1)) {
goto done;
}
@@ -1435,6 +1528,9 @@ done:
ast_channel_unlock(c0);
ast_channel_unlock(c1);
+ ast_format_cap_destroy(cap0);
+ ast_format_cap_destroy(cap1);
+
unref_instance_cond(&instance0);
unref_instance_cond(&instance1);
unref_instance_cond(&vinstance0);
@@ -1455,11 +1551,14 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1
struct ast_rtp_glue *glue0, *glue1;
enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID, text_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID, text_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
- format_t codec0 = 0, codec1 = 0;
+ struct ast_format_cap *cap0 = ast_format_cap_alloc_nolock();
+ struct ast_format_cap *cap1 = ast_format_cap_alloc_nolock();
int res = 0;
/* If there is no second channel just immediately bail out, we are of no use in that scenario */
if (!c1) {
+ ast_format_cap_destroy(cap0);
+ ast_format_cap_destroy(cap1);
return -1;
}
@@ -1471,6 +1570,10 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1
ast_channel_lock(c0);
}
+ if (!cap1 || !cap0) {
+ goto done;
+ }
+
/* Grab glue that binds each channel to something using the RTP engine */
if (!(glue0 = ast_rtp_instance_get_glue(c0->tech->type)) || !(glue1 = ast_rtp_instance_get_glue(c1->tech->type))) {
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", glue0 ? c1->name : c0->name);
@@ -1492,11 +1595,11 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1
if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
}
- if (audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE) && glue0->get_codec(c0)) {
- codec0 = glue0->get_codec(c0);
+ if (audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE) && glue0->get_codec) {
+ glue0->get_codec(c0, cap0);
}
- if (audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) && glue1->get_codec(c1)) {
- codec1 = glue1->get_codec(c1);
+ if (audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) && glue1->get_codec) {
+ glue1->get_codec(c1, cap1);
}
/* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
@@ -1505,12 +1608,12 @@ int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1
}
/* Make sure we have matching codecs */
- if (!(codec0 & codec1)) {
+ if (!ast_format_cap_has_joint(cap0, cap1)) {
goto done;
}
/* Bridge media early */
- if (glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0)) {
+ if (glue0->update_peer(c0, instance1, vinstance1, tinstance1, cap1, 0)) {
ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
}
@@ -1520,6 +1623,9 @@ done:
ast_channel_unlock(c0);
ast_channel_unlock(c1);
+ ast_format_cap_destroy(cap0);
+ ast_format_cap_destroy(cap1);
+
unref_instance_cond(&instance0);
unref_instance_cond(&instance1);
unref_instance_cond(&vinstance0);
@@ -1623,12 +1729,12 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in
}
}
-int ast_rtp_instance_set_read_format(struct ast_rtp_instance *instance, format_t format)
+int ast_rtp_instance_set_read_format(struct ast_rtp_instance *instance, struct ast_format *format)
{
return instance->engine->set_read_format ? instance->engine->set_read_format(instance, format) : -1;
}
-int ast_rtp_instance_set_write_format(struct ast_rtp_instance *instance, format_t format)
+int ast_rtp_instance_set_write_format(struct ast_rtp_instance *instance, struct ast_format *format)
{
return instance->engine->set_write_format ? instance->engine->set_write_format(instance, format) : -1;
}
@@ -1669,15 +1775,16 @@ int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_in
return res;
}
-format_t ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, format_t to_endpoint, format_t to_asterisk)
+void ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, struct ast_format_cap *to_endpoint, struct ast_format_cap *to_asterisk, struct ast_format_cap *result)
{
- format_t formats;
-
- if (instance->engine->available_formats && (formats = instance->engine->available_formats(instance, to_endpoint, to_asterisk))) {
- return formats;
+ if (instance->engine->available_formats) {
+ instance->engine->available_formats(instance, to_endpoint, to_asterisk, result);
+ if (!ast_format_cap_is_empty(result)) {
+ return;
+ }
}
- return ast_translate_available_formats(to_endpoint, to_asterisk);
+ ast_translate_available_formats(to_endpoint, to_asterisk, result);
}
int ast_rtp_instance_activate(struct ast_rtp_instance *instance)
diff --git a/main/slinfactory.c b/main/slinfactory.c
index 4da443af5..f7363ab4b 100644
--- a/main/slinfactory.c
+++ b/main/slinfactory.c
@@ -36,7 +36,7 @@ void ast_slinfactory_init(struct ast_slinfactory *sf)
{
memset(sf, 0, sizeof(*sf));
sf->offset = sf->hold;
- sf->output_format = AST_FORMAT_SLINEAR;
+ ast_format_set(&sf->output_format, AST_FORMAT_SLINEAR, 0);
}
int ast_slinfactory_init_rate(struct ast_slinfactory *sf, unsigned int sample_rate)
@@ -45,10 +45,10 @@ int ast_slinfactory_init_rate(struct ast_slinfactory *sf, unsigned int sample_ra
sf->offset = sf->hold;
switch (sample_rate) {
case 8000:
- sf->output_format = AST_FORMAT_SLINEAR;
+ ast_format_set(&sf->output_format, AST_FORMAT_SLINEAR, 0);
break;
case 16000:
- sf->output_format = AST_FORMAT_SLINEAR16;
+ ast_format_set(&sf->output_format, AST_FORMAT_SLINEAR16, 0);
break;
default:
return -1;
@@ -85,19 +85,19 @@ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
return 0;
}
- if (f->subclass.codec != sf->output_format) {
- if (sf->trans && f->subclass.codec != sf->format) {
+ if (ast_format_cmp(&f->subclass.format, &sf->output_format) == AST_FORMAT_CMP_NOT_EQUAL) {
+ if (sf->trans && (ast_format_cmp(&f->subclass.format, &sf->format) == AST_FORMAT_CMP_NOT_EQUAL)) {
ast_translator_free_path(sf->trans);
sf->trans = NULL;
}
if (!sf->trans) {
- if (!(sf->trans = ast_translator_build_path(sf->output_format, f->subclass.codec))) {
- ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n", ast_getformatname(f->subclass.codec),
- ast_getformatname(sf->output_format));
+ if (!(sf->trans = ast_translator_build_path(&sf->output_format, &f->subclass.format))) {
+ ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n", ast_getformatname(&f->subclass.format),
+ ast_getformatname(&sf->output_format));
return 0;
}
- sf->format = f->subclass.codec;
+ ast_format_copy(&sf->format, &f->subclass.format);
}
if (!(begin_frame = ast_translate(sf->trans, f, 0))) {
diff --git a/main/translate.c b/main/translate.c
index 61b4a4686..553e70cde 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -40,31 +40,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/term.h"
-#define MAX_RECALC 1000 /* max sample recalc */
+/*! \todo
+ * TODO: sample frames for each supported input format.
+ * We build this on the fly, by taking an SLIN frame and using
+ * the existing converter to play with it.
+ */
+
+/*! max sample recalc */
+#define MAX_RECALC 1000
/*! \brief the list of translators */
static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
-
-/*! \brief these values indicate how a translation path will affect the sample rate
- *
- * \note These must stay in this order. They are ordered by most optimal selection first.
- */
-enum path_samp_change {
- RATE_CHANGE_NONE = 0, /*!< path uses the same sample rate consistently */
- RATE_CHANGE_UPSAMP = 1, /*!< path will up the sample rate during a translation */
- RATE_CHANGE_DOWNSAMP = 2, /*!< path will have to down the sample rate during a translation. */
- RATE_CHANGE_UPSAMP_DOWNSAMP = 3, /*!< path will both up and down the sample rate during translation */
-};
-
struct translator_path {
- struct ast_translator *step; /*!< Next step translator */
- unsigned int cost; /*!< Complete cost to destination */
- unsigned int multistep; /*!< Multiple conversions required for this translation */
- enum path_samp_change rate_change; /*!< does this path require a sample rate change, if so what kind. */
+ struct ast_translator *step; /*!< Next step translator */
+ uint32_t table_cost; /*!< Complete table cost to destination */
+ uint8_t multistep; /*!< Multiple conversions required for this translation */
};
-/*! \brief a matrix that, for any pair of supported formats,
+/*!
+ * \brief a matrix that, for any pair of supported formats,
* indicates the total cost of translation and the first step.
* The full path can be reconstricted iterating on the matrix
* until step->dstfmt == desired_format.
@@ -74,27 +69,202 @@ struct translator_path {
* Note: the lock in the 'translators' list is also used to protect
* this structure.
*/
-static struct translator_path tr_matrix[MAX_FORMAT][MAX_FORMAT];
+static struct translator_path **__matrix;
-/*! \todo
- * TODO: sample frames for each supported input format.
- * We build this on the fly, by taking an SLIN frame and using
- * the existing converter to play with it.
+/*!
+ * \brief table for converting index to format id values.
+ *
+ * \note this table is protected by the table_lock.
*/
+static int *__indextable;
+
+/*! protects the __indextable for resizing */
+static ast_rwlock_t tablelock;
+
+/* index size starts at this*/
+#define INIT_INDEX 32
+/* index size grows by this as necessary */
+#define GROW_INDEX 16
+
+/*! the current largest index used by the __matrix and __indextable arrays*/
+static int cur_max_index;
+/*! the largest index that can be used in either the __indextable or __matrix before resize must occur */
+static int index_size;
+
+static void matrix_rebuild(int samples);
-/*! \brief returns the index of the lowest bit set */
-static force_inline int powerof(format_t d)
+/*!
+ * \internal
+ * \brief converts format id to index value.
+ */
+static int format2index(enum ast_format_id id)
{
- int x = ffsll(d);
+ int x;
+
+ ast_rwlock_rdlock(&tablelock);
+ for (x = 0; x < cur_max_index; x++) {
+ if (__indextable[x] == id) {
+ /* format already exists in index2format table */
+ ast_rwlock_unlock(&tablelock);
+ return x;
+ }
+ }
+ ast_rwlock_unlock(&tablelock);
+ return -1; /* not found */
+}
- if (x)
- return x - 1;
+/*!
+ * \internal
+ * \brief add a new format to the matrix and index table structures.
+ *
+ * \note it is perfectly safe to call this on formats already indexed.
+ *
+ * \retval 0, success
+ * \retval -1, matrix and index table need to be resized
+ */
+static int add_format2index(enum ast_format_id id)
+{
+ if (format2index(id) != -1) {
+ /* format is already already indexed */
+ return 0;
+ }
+
+ ast_rwlock_wrlock(&tablelock);
+ if (cur_max_index == (index_size)) {
+ ast_rwlock_unlock(&tablelock);
+ return -1; /* hit max length */
+ }
+ __indextable[cur_max_index] = id;
+ cur_max_index++;
+ ast_rwlock_unlock(&tablelock);
+
+ return 0;
+}
- ast_log(LOG_WARNING, "No bits set? %llu\n", (unsigned long long) d);
+/*!
+ * \internal
+ * \brief converts index value back to format id
+ */
+static enum ast_format_id index2format(int index)
+{
+ enum ast_format_id format_id;
+
+ if (index >= cur_max_index) {
+ return 0;
+ }
+ ast_rwlock_rdlock(&tablelock);
+ format_id = __indextable[index];
+ ast_rwlock_unlock(&tablelock);
+
+ return format_id;
+}
+
+/*!
+ * \internal
+ * \brief resize both the matrix and index table so they can represent
+ * more translators
+ *
+ * \note _NO_ locks can be held prior to calling this function
+ *
+ * \retval 0, success
+ * \retval -1, failure. Old matrix and index table can still be used though
+ */
+static int matrix_resize(int init)
+{
+ struct translator_path **tmp_matrix = NULL;
+ int *tmp_table = NULL;
+ int old_index;
+ int x;
+
+ AST_RWLIST_WRLOCK(&translators);
+ ast_rwlock_wrlock(&tablelock);
+
+ old_index = index_size;
+ if (init) {
+ index_size += INIT_INDEX;
+ } else {
+ index_size += GROW_INDEX;
+ }
+
+ /* make new 2d array of translator_path structures */
+ if (!(tmp_matrix = ast_calloc(1, sizeof(struct translator_path *) * (index_size)))) {
+ goto resize_cleanup;
+ }
+
+ for (x = 0; x < index_size; x++) {
+ if (!(tmp_matrix[x] = ast_calloc(1, sizeof(struct translator_path) * (index_size)))) {
+ goto resize_cleanup;
+ }
+ }
+
+ /* make new index table */
+ if (!(tmp_table = ast_calloc(1, sizeof(int) * index_size))) {
+ goto resize_cleanup;
+ }
+
+ /* if everything went well this far, free the old and use the new */
+ if (!init) {
+ for (x = 0; x < old_index; x++) {
+ ast_free(__matrix[x]);
+ }
+ ast_free(__matrix);
+
+ memcpy(tmp_table, __indextable, sizeof(int) * old_index);
+ ast_free(__indextable);
+ }
+
+ /* now copy them over */
+ __matrix = tmp_matrix;
+ __indextable = tmp_table;
+
+ matrix_rebuild(0);
+ ast_rwlock_unlock(&tablelock);
+ AST_RWLIST_UNLOCK(&translators);
+
+ return 0;
+
+resize_cleanup:
+ ast_rwlock_unlock(&tablelock);
+ AST_RWLIST_UNLOCK(&translators);
+ if (tmp_matrix) {
+ for (x = 0; x < index_size; x++) {
+ ast_free(tmp_matrix[x]);
+ }
+ ast_free(tmp_matrix);
+ }
+ ast_free(tmp_table);
return -1;
}
+/*!
+ * \internal
+ * \brief reinitialize the __matrix during matrix rebuild
+ *
+ * \note must be protected by the translators list lock
+ */
+static void matrix_clear(void)
+{
+ int x;
+ for (x = 0; x < index_size; x++) {
+ memset(__matrix[x], '\0', sizeof(struct translator_path) * (index_size));
+ }
+}
+
+/*!
+ * \internal
+ * \brief get a matrix entry
+ *
+ * \note This function must be protected by the translators list lock
+ */
+static struct translator_path *matrix_get(unsigned int x, unsigned int y)
+{
+ if (!(x >= 0 && y >= 0)) {
+ return NULL;
+ }
+ return __matrix[x] + y;
+}
+
/*
* wrappers around the translator routines.
*/
@@ -151,7 +321,7 @@ static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
{
int ret;
int samples = pvt->samples; /* initial value */
-
+
/* Copy the last in jb timing info to the pvt */
ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO);
pvt->f.ts = f->ts;
@@ -193,23 +363,23 @@ struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
{
struct ast_frame *f = &pvt->f;
- if (samples)
+ if (samples) {
f->samples = samples;
- else {
+ } else {
if (pvt->samples == 0)
return NULL;
f->samples = pvt->samples;
pvt->samples = 0;
}
- if (datalen)
+ if (datalen) {
f->datalen = datalen;
- else {
+ } else {
f->datalen = pvt->datalen;
pvt->datalen = 0;
}
f->frametype = AST_FRAME_VOICE;
- f->subclass.codec = 1LL << (pvt->t->dstfmt);
+ ast_format_copy(&f->subclass.format, &pvt->t->dst_format);
f->mallocd = 0;
f->offset = AST_FRIENDLY_OFFSET;
f->src = pvt->t->name;
@@ -235,45 +405,56 @@ void ast_translator_free_path(struct ast_trans_pvt *p)
}
/*! \brief Build a chain of translators based upon the given source and dest formats */
-struct ast_trans_pvt *ast_translator_build_path(format_t dest, format_t source)
+struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct ast_format *src)
{
struct ast_trans_pvt *head = NULL, *tail = NULL;
-
- source = powerof(source);
- dest = powerof(dest);
+ int src_index, dst_index;
+ struct ast_format tmp_fmt1;
+ struct ast_format tmp_fmt2;
+
+ src_index = format2index(src->id);
+ dst_index = format2index(dst->id);
- if (source == -1 || dest == -1) {
- ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", source == -1 ? "starting" : "ending");
+ if (src_index == -1 || dst_index == -1) {
+ ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src_index == -1 ? "starting" : "ending");
return NULL;
}
AST_RWLIST_RDLOCK(&translators);
- while (source != dest) {
+ while (src_index != dst_index) {
struct ast_trans_pvt *cur;
- struct ast_translator *t = tr_matrix[source][dest].step;
+ struct ast_translator *t = matrix_get(src_index, dst_index)->step;
if (!t) {
- ast_log(LOG_WARNING, "No translator path from %s to %s\n",
- ast_getformatname(source), ast_getformatname(dest));
+ int src_id = index2format(src_index);
+ int dst_id = index2format(dst_index);
+ ast_log(LOG_WARNING, "No translator path from %s to %s\n",
+ ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
+ ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
AST_RWLIST_UNLOCK(&translators);
return NULL;
}
if (!(cur = newpvt(t))) {
+ int src_id = index2format(src_index);
+ int dst_id = index2format(dst_index);
ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
- ast_getformatname(source), ast_getformatname(dest));
- if (head)
- ast_translator_free_path(head);
+ ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
+ ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
+ if (head) {
+ ast_translator_free_path(head);
+ }
AST_RWLIST_UNLOCK(&translators);
return NULL;
}
- if (!head)
+ if (!head) {
head = cur;
- else
+ } else {
tail->next = cur;
+ }
tail = cur;
cur->nextin = cur->nextout = ast_tv(0, 0);
/* Keep going if this isn't the final destination */
- source = cur->t->dstfmt;
+ src_index = cur->t->dst_fmt_index;
}
AST_RWLIST_UNLOCK(&translators);
@@ -284,7 +465,7 @@ struct ast_trans_pvt *ast_translator_build_path(format_t dest, format_t source)
struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
{
struct ast_trans_pvt *p = path;
- struct ast_frame *out = f;
+ struct ast_frame *out;
struct timeval delivery;
int has_timing_info;
long ts;
@@ -296,7 +477,6 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
len = f->len;
seqno = f->seqno;
- /* XXX hmmm... check this below */
if (!ast_tvzero(f->delivery)) {
if (!ast_tvzero(path->nextin)) {
/* Make sure this is in line with what we were expecting */
@@ -316,31 +496,35 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
path->nextout = f->delivery;
}
/* Predict next incoming sample */
- path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(f->subclass.codec)));
+ path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(&f->subclass.format)));
}
delivery = f->delivery;
- for ( ; out && p ; p = p->next) {
+ for (out = f; out && p ; p = p->next) {
framein(p, out);
- if (out != f)
+ if (out != f) {
ast_frfree(out);
+ }
out = p->t->frameout(p);
}
- if (consume)
+ if (consume) {
ast_frfree(f);
- if (out == NULL)
+ }
+ if (out == NULL) {
return NULL;
+ }
/* we have a frame, play with times */
if (!ast_tvzero(delivery)) {
/* Regenerate prediction after a discontinuity */
- if (ast_tvzero(path->nextout))
+ if (ast_tvzero(path->nextout)) {
path->nextout = ast_tvnow();
+ }
/* Use next predicted outgoing timestamp */
out->delivery = path->nextout;
-
+
/* Predict next outgoing timestamp from samples in this
frame. */
- path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(out->subclass.codec)));
+ path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(&out->subclass.format)));
} else {
out->delivery = ast_tv(0, 0);
ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
@@ -351,35 +535,45 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
}
}
/* Invalidate prediction if we're entering a silence period */
- if (out->frametype == AST_FRAME_CNG)
+ if (out->frametype == AST_FRAME_CNG) {
path->nextout = ast_tv(0, 0);
+ }
return out;
}
-/*! \brief compute the cost of a single translation step */
-static void calc_cost(struct ast_translator *t, int seconds)
+/*!
+ * \internal
+ * \brief Compute the computational cost of a single translation step.
+ *
+ * \note This function is only used to decide which translation path to
+ * use between two translators with identical src and dst formats. Computational
+ * cost acts only as a tie breaker. This is done so hardware translators
+ * can naturally have precedence over software translators.
+ */
+static void generate_computational_cost(struct ast_translator *t, int seconds)
{
int num_samples = 0;
struct ast_trans_pvt *pvt;
struct rusage start;
struct rusage end;
int cost;
- int out_rate = ast_format_rate(t->dstfmt);
+ int out_rate = ast_format_rate(&t->dst_format);
- if (!seconds)
+ if (!seconds) {
seconds = 1;
-
+ }
+
/* If they don't make samples, give them a terrible score */
if (!t->sample) {
ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
- t->cost = 999999;
+ t->comp_cost = 999999;
return;
}
pvt = newpvt(t);
if (!pvt) {
ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
- t->cost = 999999;
+ t->comp_cost = 999999;
return;
}
@@ -391,7 +585,7 @@ static void calc_cost(struct ast_translator *t, int seconds)
if (!f) {
ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
destroy(pvt);
- t->cost = 999999;
+ t->comp_cost = 999999;
return;
}
framein(pvt, f);
@@ -409,72 +603,127 @@ static void calc_cost(struct ast_translator *t, int seconds)
destroy(pvt);
- t->cost = cost / seconds;
+ t->comp_cost = cost / seconds;
- if (!t->cost)
- t->cost = 1;
+ if (!t->comp_cost) {
+ t->comp_cost = 1;
+ }
}
-static enum path_samp_change get_rate_change_result(format_t src, format_t dst)
+/*!
+ * \internal
+ *
+ * \brief If no table cost value was pre set by the translator. An attempt is made to
+ * automatically generate that cost value from the cost table based on our src and
+ * dst formats.
+ *
+ * \note This function allows older translators built before the translation cost
+ * changed away from using onely computational time to continue to be registered
+ * correctly. It is expected that translators built after the introduction of this
+ * function will manually assign their own table cost value.
+ *
+ * \note This function is safe to use on any audio formats that used to be defined in the
+ * first 64 bits of the old bit field codec representation.
+ *
+ * \retval Table Cost value greater than 0.
+ * \retval 0 on error.
+ */
+static int generate_table_cost(struct ast_format *src, struct ast_format *dst)
{
int src_rate = ast_format_rate(src);
+ int src_ll = 0;
int dst_rate = ast_format_rate(dst);
+ int dst_ll = 0;
- /* if src rate is less than dst rate, a sample upgrade is required */
- if (src_rate < dst_rate) {
- return RATE_CHANGE_UPSAMP;
+ if ((AST_FORMAT_GET_TYPE(src->id) != AST_FORMAT_TYPE_AUDIO) || (AST_FORMAT_GET_TYPE(dst->id) != AST_FORMAT_TYPE_AUDIO)) {
+ /* This method of generating table cost is limited to audio.
+ * Translators for media other than audio must manually set their
+ * table cost. */
+ return 0;
}
-
- /* if src rate is larger than dst rate, a downgrade is required */
- if (src_rate > dst_rate) {
- return RATE_CHANGE_DOWNSAMP;
+ if ((src->id == AST_FORMAT_SLINEAR) || (src->id == AST_FORMAT_SLINEAR16)) {
+ src_ll = 1;
+ }
+ if ((dst->id == AST_FORMAT_SLINEAR) || (dst->id == AST_FORMAT_SLINEAR16)) {
+ dst_ll = 1;
}
- return RATE_CHANGE_NONE;
+ if (src_ll) {
+ if (dst_ll && (src_rate == dst_rate)) {
+ return AST_TRANS_COST_LL_LL_ORIGSAMP;
+ } else if (!dst_ll && (src_rate == dst_rate)) {
+ return AST_TRANS_COST_LL_LY_ORIGSAMP;
+ } else if (dst_ll && (src_rate < dst_rate)) {
+ return AST_TRANS_COST_LL_LL_UPSAMP;
+ } else if (!dst_ll && (src_rate < dst_rate)) {
+ return AST_TRANS_COST_LL_LY_UPSAMP;
+ } else if (dst_ll && (src_rate > dst_rate)) {
+ return AST_TRANS_COST_LL_LL_DOWNSAMP;
+ } else if (!dst_ll && (src_rate > dst_rate)) {
+ return AST_TRANS_COST_LL_LY_DOWNSAMP;
+ } else {
+ return AST_TRANS_COST_LL_UNKNOWN;
+ }
+ } else {
+ if (dst_ll && (src_rate == dst_rate)) {
+ return AST_TRANS_COST_LY_LL_ORIGSAMP;
+ } else if (!dst_ll && (src_rate == dst_rate)) {
+ return AST_TRANS_COST_LY_LY_ORIGSAMP;
+ } else if (dst_ll && (src_rate < dst_rate)) {
+ return AST_TRANS_COST_LY_LL_UPSAMP;
+ } else if (!dst_ll && (src_rate < dst_rate)) {
+ return AST_TRANS_COST_LY_LY_UPSAMP;
+ } else if (dst_ll && (src_rate > dst_rate)) {
+ return AST_TRANS_COST_LY_LL_DOWNSAMP;
+ } else if (!dst_ll && (src_rate > dst_rate)) {
+ return AST_TRANS_COST_LY_LY_DOWNSAMP;
+ } else {
+ return AST_TRANS_COST_LY_UNKNOWN;
+ }
+ }
}
/*!
* \brief rebuild a translation matrix.
* \note This function expects the list of translators to be locked
*/
-static void rebuild_matrix(int samples)
+static void matrix_rebuild(int samples)
{
struct ast_translator *t;
- int new_rate_change;
- int newcost;
+ int newtablecost;
int x; /* source format index */
int y; /* intermediate format index */
int z; /* destination format index */
ast_debug(1, "Resetting translation matrix\n");
- memset(tr_matrix, '\0', sizeof(tr_matrix));
+ matrix_clear();
/* first, compute all direct costs */
AST_RWLIST_TRAVERSE(&translators, t, list) {
- if (!t->active)
+ if (!t->active) {
continue;
+ }
- x = t->srcfmt;
- z = t->dstfmt;
-
- if (samples)
- calc_cost(t, samples);
+ x = t->src_fmt_index;
+ z = t->dst_fmt_index;
- new_rate_change = get_rate_change_result(1LL << t->srcfmt, 1LL << t->dstfmt);
+ if (samples) {
+ generate_computational_cost(t, samples);
+ }
- /* this translator is the best choice if any of the below are true.
+ /* This new translator is the best choice if any of the below are true.
* 1. no translation path is set between x and z yet.
- * 2. the new translation costs less and sample rate is no worse than old one.
- * 3. the new translation has a better sample rate conversion than the old one.
+ * 2. the new table cost is less.
+ * 3. the new computational cost is less. Computational cost is only used
+ * to break a tie between two identical translation paths.
*/
- if (!tr_matrix[x][z].step ||
- ((t->cost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) ||
- (new_rate_change < tr_matrix[x][z].rate_change)) {
+ if (!matrix_get(x, z)->step ||
+ (t->table_cost < matrix_get(x, z)->step->table_cost) ||
+ (t->comp_cost < matrix_get(x, z)->step->comp_cost)) {
- tr_matrix[x][z].step = t;
- tr_matrix[x][z].cost = t->cost;
- tr_matrix[x][z].rate_change = new_rate_change;
+ matrix_get(x, z)->step = t;
+ matrix_get(x, z)->table_cost = t->table_cost;
}
}
@@ -486,81 +735,43 @@ static void rebuild_matrix(int samples)
*/
for (;;) {
int changed = 0;
- int better_choice = 0;
- for (x = 0; x < MAX_FORMAT; x++) { /* source format */
- for (y = 0; y < MAX_FORMAT; y++) { /* intermediate format */
- if (x == y) /* skip ourselves */
+ for (x = 0; x < cur_max_index; x++) { /* source format */
+ for (y = 0; y < cur_max_index; y++) { /* intermediate format */
+ if (x == y) { /* skip ourselves */
continue;
- for (z = 0; z < MAX_FORMAT; z++) { /* dst format */
- if (z == x || z == y) /* skip null conversions */
- continue;
- if (!tr_matrix[x][y].step) /* no path from x to y */
- continue;
- if (!tr_matrix[y][z].step) /* no path from y to z */
- continue;
-
- /* Does x->y->z result in a less optimal sample rate change?
- * Never downgrade the sample rate conversion quality regardless
- * of any cost improvements */
- if (tr_matrix[x][z].step &&
- ((tr_matrix[x][z].rate_change < tr_matrix[x][y].rate_change) ||
- (tr_matrix[x][z].rate_change < tr_matrix[y][z].rate_change))) {
+ }
+ for (z = 0; z < cur_max_index; z++) { /* dst format */
+ if ((z == x || z == y) || /* skip null conversions */
+ !matrix_get(x, y)->step || /* no path from x to y */
+ !matrix_get(y, z)->step) { /* no path from y to z */
continue;
}
- /* is x->y->z a better sample rate confersion that the current x->z? */
- new_rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change;
-
- /* calculate cost from x->y->z */
- newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
-
- /* Is x->y->z a better choice than x->z?
- * There are three conditions for x->y->z to be a better choice than x->z
- * 1. if there is no step directly between x->z then x->y->z is the best and only current option.
- * 2. if x->y->z costs less and the sample rate conversion is no less optimal.
- * 3. if x->y->z results in a more optimal sample rate conversion. */
- if (!tr_matrix[x][z].step) {
- better_choice = 1;
- } else if ((newcost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) {
- better_choice = 1;
- } else if (new_rate_change < tr_matrix[x][z].rate_change) {
- better_choice = 1;
- } else {
- better_choice = 0;
+ /* calculate table cost from x->y->z */
+ newtablecost = matrix_get(x, y)->table_cost + matrix_get(y, z)->table_cost;
+
+ /* if no step already exists between x and z OR the new cost of using the intermediate
+ * step is cheaper, use this step. */
+ if (!matrix_get(x, z)->step || (newtablecost < matrix_get(x, z)->table_cost)) {
+ struct ast_format tmpx;
+ struct ast_format tmpy;
+ struct ast_format tmpz;
+ matrix_get(x, z)->step = matrix_get(x, y)->step;
+ matrix_get(x, z)->table_cost = newtablecost;
+ matrix_get(x, z)->multistep = 1;
+ changed++;
+ ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n",
+ matrix_get(x, z)->table_cost,
+ ast_getformatname(ast_format_set(&tmpx, index2format(x), 0)),
+ ast_getformatname(ast_format_set(&tmpy, index2format(z), 0)),
+ ast_getformatname(ast_format_set(&tmpz, index2format(y), 0)));
}
-
- if (!better_choice) {
- continue;
- }
- /* ok, we can get from x to z via y with a cost that
- is the sum of the transition from x to y and from y to z */
- tr_matrix[x][z].step = tr_matrix[x][y].step;
- tr_matrix[x][z].cost = newcost;
- tr_matrix[x][z].multistep = 1;
-
- /* now calculate what kind of sample rate change is required for this multi-step path
- *
- * if both paths require a change in rate, and they are not in the same direction
- * then this is a up sample down sample conversion scenario. */
- if ((tr_matrix[x][y].rate_change > RATE_CHANGE_NONE) &&
- (tr_matrix[y][z].rate_change > RATE_CHANGE_NONE) &&
- (tr_matrix[x][y].rate_change != tr_matrix[y][z].rate_change)) {
-
- tr_matrix[x][z].rate_change = RATE_CHANGE_UPSAMP_DOWNSAMP;
- } else {
- /* else just set the rate change to whichever is worse */
- tr_matrix[x][z].rate_change = tr_matrix[x][y].rate_change > tr_matrix[y][z].rate_change
- ? tr_matrix[x][y].rate_change : tr_matrix[y][z].rate_change;
- }
-
- ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost,
- ast_getformatname(1LL << x), ast_getformatname(1LL << z), ast_getformatname(1LL << y));
- changed++;
}
}
}
- if (!changed)
+ if (!changed) {
break;
+ }
}
}
@@ -572,11 +783,11 @@ const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **
return "";
}
- ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt));
+ ast_str_set(str, 0, "%s", ast_getformatname(&p->t->src_format));
while ( (p = pn) ) {
pn = p->next;
- ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt));
+ ast_str_append(str, 0, "->%s", ast_getformatname(&p->t->dst_format));
}
return ast_str_buffer(*str);
@@ -592,7 +803,7 @@ static char *complete_trans_path_choice(const char *line, const char *word, int
const struct ast_format_list *format_list = ast_get_format_list(&len);
for (i = 0; i < len; i++) {
- if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
+ if (AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) {
continue;
}
if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
@@ -603,165 +814,81 @@ static char *complete_trans_path_choice(const char *line, const char *word, int
return ret;
}
-static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static void handle_cli_recalc(struct ast_cli_args *a)
{
-#define SHOW_TRANS 64
- static const char * const option1[] = { "recalc", "paths", NULL };
- int x, y, z;
- int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, };
+ int time = a->argv[4] ? atoi(a->argv[4]) : 1;
- switch (cmd) {
- case CLI_INIT:
- e->command = "core show translation";
- e->usage =
- "Usage: 'core show translation' can be used in two ways.\n"
- " 1. 'core show translation [recalc [<recalc seconds>]]\n"
- " Displays known codec translators and the cost associated\n"
- " with each conversion. If the argument 'recalc' is supplied along\n"
- " with optional number of seconds to test a new test will be performed\n"
- " as the chart is being displayed.\n"
- " 2. 'core show translation paths [codec]'\n"
- " This will display all the translation paths associated with a codec\n";
- return NULL;
- case CLI_GENERATE:
- if (a->pos == 3) {
- return ast_cli_complete(a->word, option1, a->n);
- }
- if (a->pos == 4 && !strcasecmp(a->argv[3], option1[1])) {
- return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
- }
- return NULL;
+ if (time <= 0) {
+ ast_cli(a->fd, " Recalc must be greater than 0. Defaulting to 1.\n");
+ time = 1;
}
- if (a->argc > 5)
- return CLI_SHOWUSAGE;
-
- if (a->argv[3] && !strcasecmp(a->argv[3], option1[1]) && a->argc == 5) {
- format_t input_src = 0;
- format_t src = 0;
- size_t len = 0;
- int dst;
- int i;
- const struct ast_format_list *format_list = ast_get_format_list(&len);
- struct ast_str *str = ast_str_alloca(256);
- struct ast_translator *step;
-
- for (i = 0; i < len; i++) {
- if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
- continue;
- }
- if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
- input_src = format_list[i].bits;
- }
- }
-
- if (!input_src) {
- ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
- return CLI_FAILURE;
- }
-
- AST_RWLIST_RDLOCK(&translators);
- ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(input_src));
- for (i = 0; i < len; i++) {
- if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK) || (format_list[i].bits == input_src)) {
- continue;
- }
- dst = powerof(format_list[i].bits);
- src = powerof(input_src);
- ast_str_reset(str);
- if (tr_matrix[src][dst].step) {
- ast_str_append(&str, 0, "%s", ast_getformatname(1LL << tr_matrix[src][dst].step->srcfmt));
- while (src != dst) {
- step = tr_matrix[src][dst].step;
- if (!step) {
- ast_str_reset(str);
- break;
- }
- ast_str_append(&str, 0, "->%s", ast_getformatname(1LL << step->dstfmt));
- src = step->dstfmt;
- }
- }
-
- if (ast_strlen_zero(ast_str_buffer(str))) {
- ast_str_set(&str, 0, "No Translation Path");
- }
-
- ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
- }
- AST_RWLIST_UNLOCK(&translators);
-
- return CLI_SUCCESS;
- } else if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
- z = a->argv[4] ? atoi(a->argv[4]) : 1;
-
- if (z <= 0) {
- ast_cli(a->fd, " Recalc must be greater than 0. Defaulting to 1.\n");
- z = 1;
- }
-
- if (z > MAX_RECALC) {
- ast_cli(a->fd, " Maximum limit of recalc exceeded by %d, truncating value to %d\n", z - MAX_RECALC, MAX_RECALC);
- z = MAX_RECALC;
- }
- ast_cli(a->fd, " Recalculating Codec Translation (number of sample seconds: %d)\n\n", z);
- AST_RWLIST_WRLOCK(&translators);
- rebuild_matrix(z);
- AST_RWLIST_UNLOCK(&translators);
- } else if (a->argc > 3)
- return CLI_SHOWUSAGE;
+ if (time > MAX_RECALC) {
+ ast_cli(a->fd, " Maximum limit of recalc exceeded by %d, truncating value to %d\n", time - MAX_RECALC, MAX_RECALC);
+ time = MAX_RECALC;
+ }
+ ast_cli(a->fd, " Recalculating Codec Translation (number of sample seconds: %d)\n\n", time);
+ AST_RWLIST_WRLOCK(&translators);
+ matrix_rebuild(time);
+ AST_RWLIST_UNLOCK(&translators);
+}
+static char *handle_show_translation_table(struct ast_cli_args *a)
+{
+ int x, y;
+ int curlen = 0, longest = 0;
+ struct ast_format tmp_fmt;
AST_RWLIST_RDLOCK(&translators);
-
ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n");
ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n");
+
/* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
- for (x = 0; x < SHOW_TRANS; x++) {
+ for (x = 0; x < cur_max_index; x++) {
/* translation only applies to audio right now. */
- if (!(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
+ if (AST_FORMAT_GET_TYPE(index2format(x)) != AST_FORMAT_TYPE_AUDIO)
continue;
- curlen = strlen(ast_getformatname(1LL << (x)));
- if (curlen > longest)
+ curlen = strlen(ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)));
+ if (curlen > longest) {
longest = curlen;
- for (y = 0; y < SHOW_TRANS; y++) {
- if (!(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
- continue;
- if (tr_matrix[x][y].cost > pow(10, magnitude[x])) {
- magnitude[y] = floor(log10(tr_matrix[x][y].cost));
- }
}
}
- for (x = -1; x < SHOW_TRANS; x++) {
+
+ for (x = -1; x < cur_max_index; x++) {
struct ast_str *out = ast_str_alloca(256);
/* translation only applies to audio right now. */
- if (x >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
+ if (x >= 0 && (AST_FORMAT_GET_TYPE(index2format(x)) != AST_FORMAT_TYPE_AUDIO)) {
continue;
+ }
/*Go ahead and move to next iteration if dealing with an unknown codec*/
- if(x >= 0 && !strcmp(ast_getformatname(1LL << (x)), "unknown"))
+ if (x >= 0 && !strcmp(ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)), "unknown")) {
continue;
+ }
ast_str_set(&out, -1, " ");
- for (y = -1; y < SHOW_TRANS; y++) {
+ for (y = -1; y < cur_max_index; y++) {
/* translation only applies to audio right now. */
- if (y >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
+ if (y >= 0 && (AST_FORMAT_GET_TYPE(index2format(y)) != AST_FORMAT_TYPE_AUDIO)) {
continue;
+ }
/*Go ahead and move to next iteration if dealing with an unknown codec*/
- if (y >= 0 && !strcmp(ast_getformatname(1LL << (y)), "unknown"))
+ if (y >= 0 && !strcmp(ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)), "unknown")) {
continue;
- if (y >= 0)
- curlen = strlen(ast_getformatname(1LL << (y)));
- if (y >= 0 && magnitude[y] + 1 > curlen) {
- curlen = magnitude[y] + 1;
}
- if (curlen < 5)
+ if (y >= 0) {
+ curlen = strlen(ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)));
+ }
+ if (curlen < 5) {
curlen = 5;
- if (x >= 0 && y >= 0 && tr_matrix[x][y].step) {
+ }
+
+ if (x >= 0 && y >= 0 && matrix_get(x, y)->step) {
/* Actual codec output */
- ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost);
+ ast_str_append(&out, -1, "%*d", curlen + 1, (matrix_get(x, y)->table_cost/100));
} else if (x == -1 && y >= 0) {
/* Top row - use a dynamic size */
- ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1LL << (y)) );
+ ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)));
} else if (y == -1 && x >= 0) {
/* Left column - use a static size. */
- ast_str_append(&out, -1, "%*s", longest, ast_getformatname(1LL << (x)) );
+ ast_str_append(&out, -1, "%*s", longest, ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)));
} else if (x >= 0 && y >= 0) {
/* Codec not supported */
ast_str_append(&out, -1, "%*s", curlen + 1, "-");
@@ -777,6 +904,106 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
return CLI_SUCCESS;
}
+static char *handle_show_translation_path(struct ast_cli_args *a)
+{
+ struct ast_format input_src_format;
+ size_t len = 0;
+ int i;
+ const struct ast_format_list *format_list = ast_get_format_list(&len);
+ struct ast_str *str = ast_str_alloca(256);
+ struct ast_translator *step;
+
+ ast_format_clear(&input_src_format);
+
+ for (i = 0; i < len; i++) {
+ if (AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) {
+ continue;
+ }
+ if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
+ ast_format_set(&input_src_format, format_list[i].id, 0);
+ }
+ }
+
+ if (!input_src_format.id) {
+ ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
+ return CLI_FAILURE;
+ }
+
+ AST_RWLIST_RDLOCK(&translators);
+ ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(&input_src_format));
+ for (i = 0; i < len; i++) {
+ int src;
+ int dst;
+ if ((AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].id == input_src_format.id)) {
+ continue;
+ }
+ dst = format2index(format_list[i].id);
+ src = format2index(input_src_format.id);
+ ast_str_reset(str);
+ if ((len >= cur_max_index) && (src != -1) && (dst != -1) && matrix_get(src, dst)->step) {
+ ast_str_append(&str, 0, "%s", ast_getformatname(&matrix_get(src, dst)->step->src_format));
+ while (src != dst) {
+ step = matrix_get(src, dst)->step;
+ if (!step) {
+ ast_str_reset(str);
+ break;
+ }
+ ast_str_append(&str, 0, "->%s", ast_getformatname(&step->dst_format));
+ src = step->dst_fmt_index;
+ }
+ }
+
+ if (ast_strlen_zero(ast_str_buffer(str))) {
+ ast_str_set(&str, 0, "No Translation Path");
+ }
+ ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
+ }
+ AST_RWLIST_UNLOCK(&translators);
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ static const char * const option[] = { "recalc", "paths", NULL };
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core show translation";
+ e->usage =
+ "Usage: 'core show translation' can be used in two ways.\n"
+ " 1. 'core show translation [recalc [<recalc seconds>]]\n"
+ " Displays known codec translators and the cost associated\n"
+ " with each conversion. If the argument 'recalc' is supplied along\n"
+ " with optional number of seconds to test a new test will be performed\n"
+ " as the chart is being displayed.\n"
+ " 2. 'core show translation paths [codec]'\n"
+ " This will display all the translation paths associated with a codec\n";
+ return NULL;
+ case CLI_GENERATE:
+ if (a->pos == 3) {
+ return ast_cli_complete(a->word, option, a->n);
+ }
+ if (a->pos == 4 && !strcasecmp(a->argv[3], option[1])) {
+ return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
+ }
+ return NULL;
+ }
+
+ if (a->argc > 5)
+ return CLI_SHOWUSAGE;
+
+ if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 5) { /* show paths */
+ return handle_show_translation_path(a);
+ } else if (a->argv[3] && !strcasecmp(a->argv[3], option[0])) { /* recalc and then fall through to show table */
+ handle_cli_recalc(a);
+ } else if (a->argc > 3) { /* wrong input */
+ return CLI_SHOWUSAGE;
+ }
+
+ return handle_show_translation_table(a);
+}
+
static struct ast_cli_entry cli_translate[] = {
AST_CLI_DEFINE(handle_cli_core_show_translation, "Display translation matrix")
};
@@ -784,10 +1011,18 @@ static struct ast_cli_entry cli_translate[] = {
/*! \brief register codec translator */
int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
{
- static int added_cli = 0;
struct ast_translator *u;
char tmp[80];
+ if (add_format2index(t->src_format.id) || add_format2index(t->dst_format.id)) {
+ if (matrix_resize(0)) {
+ ast_log(LOG_WARNING, "Translator matrix can not represent any more translators. Out of resources.\n");
+ return -1;
+ }
+ add_format2index(t->src_format.id);
+ add_format2index(t->dst_format.id);
+ }
+
if (!mod) {
ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
return -1;
@@ -797,24 +1032,28 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
return -1;
}
+ if (!t->table_cost && !(t->table_cost = generate_table_cost(&t->src_format, &t->dst_format))) {
+ ast_log(LOG_WARNING, "Table cost could not be generated for %s, "
+ "Please set table_cost variable on translator.\n", t->name);
+ return -1;
+ }
t->module = mod;
-
- t->srcfmt = powerof(t->srcfmt);
- t->dstfmt = powerof(t->dstfmt);
+ t->src_fmt_index = format2index(t->src_format.id);
+ t->dst_fmt_index = format2index(t->dst_format.id);
t->active = 1;
- if (t->srcfmt == -1 || t->dstfmt == -1) {
- ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->srcfmt == -1 ? "starting" : "ending");
+ if (t->src_fmt_index == -1 || t->dst_fmt_index == -1) {
+ ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->src_fmt_index == -1 ? "starting" : "ending");
return -1;
}
- if (t->srcfmt >= MAX_FORMAT) {
- ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
+ if (t->src_fmt_index >= cur_max_index) {
+ ast_log(LOG_WARNING, "Source format %s is larger than cur_max_index\n", ast_getformatname(&t->src_format));
return -1;
}
- if (t->dstfmt >= MAX_FORMAT) {
- ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
+ if (t->dst_fmt_index >= cur_max_index) {
+ ast_log(LOG_WARNING, "Destination format %s is larger than cur_max_index\n", ast_getformatname(&t->dst_format));
return -1;
}
@@ -829,28 +1068,24 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
t->buf_size = ((t->buf_size + align - 1) / align) * align;
}
- if (t->frameout == NULL)
+ if (t->frameout == NULL) {
t->frameout = default_frameout;
-
- calc_cost(t, 1);
+ }
- ast_verb(2, "Registered translator '%s' from format %s to %s, cost %d\n",
- term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
- ast_getformatname(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt), t->cost);
+ generate_computational_cost(t, 1);
- if (!added_cli) {
- ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
- added_cli++;
- }
+ ast_verb(2, "Registered translator '%s' from format %s to %s, table cost, %d, computational cost %d\n",
+ term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
+ ast_getformatname(&t->src_format), ast_getformatname(&t->dst_format), t->table_cost, t->comp_cost);
AST_RWLIST_WRLOCK(&translators);
/* find any existing translators that provide this same srcfmt/dstfmt,
- and put this one in order based on cost */
+ and put this one in order based on computational cost */
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
- if ((u->srcfmt == t->srcfmt) &&
- (u->dstfmt == t->dstfmt) &&
- (u->cost > t->cost)) {
+ if ((u->src_fmt_index == t->src_fmt_index) &&
+ (u->dst_fmt_index == t->dst_fmt_index) &&
+ (u->comp_cost > t->comp_cost)) {
AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
t = NULL;
break;
@@ -860,10 +1095,11 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
/* if no existing translator was found for this format combination,
add it to the beginning of the list */
- if (t)
+ if (t) {
AST_RWLIST_INSERT_HEAD(&translators, t, list);
+ }
- rebuild_matrix(0);
+ matrix_rebuild(0);
AST_RWLIST_UNLOCK(&translators);
@@ -881,15 +1117,19 @@ int ast_unregister_translator(struct ast_translator *t)
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
if (u == t) {
AST_RWLIST_REMOVE_CURRENT(list);
- ast_verb(2, "Unregistered translator '%s' from format %s to %s\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt));
+ ast_verb(2, "Unregistered translator '%s' from format %s to %s\n",
+ term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
+ ast_getformatname(&t->src_format),
+ ast_getformatname(&t->dst_format));
found = 1;
break;
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
- if (found)
- rebuild_matrix(0);
+ if (found) {
+ matrix_rebuild(0);
+ }
AST_RWLIST_UNLOCK(&translators);
@@ -900,7 +1140,7 @@ void ast_translator_activate(struct ast_translator *t)
{
AST_RWLIST_WRLOCK(&translators);
t->active = 1;
- rebuild_matrix(0);
+ matrix_rebuild(0);
AST_RWLIST_UNLOCK(&translators);
}
@@ -908,93 +1148,93 @@ void ast_translator_deactivate(struct ast_translator *t)
{
AST_RWLIST_WRLOCK(&translators);
t->active = 0;
- rebuild_matrix(0);
+ matrix_rebuild(0);
AST_RWLIST_UNLOCK(&translators);
}
/*! \brief Calculate our best translator source format, given costs, and a desired destination */
-format_t ast_translator_best_choice(format_t *dst, format_t *srcs)
+int ast_translator_best_choice(struct ast_format_cap *dst_cap,
+ struct ast_format_cap *src_cap,
+ struct ast_format *dst_fmt_out,
+ struct ast_format *src_fmt_out)
{
- int x,y;
- int better = 0;
- int besttime = INT_MAX;
- int beststeps = INT_MAX;
- unsigned int best_rate_change = INT_MAX;
- format_t best = -1;
- format_t bestdst = 0;
- format_t cur, cursrc;
- format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */
-
- if (common) { /* yes, pick one and return */
- for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
- if (!(cur & common)) {
- continue;
- }
-
+ unsigned int besttablecost = INT_MAX;
+ unsigned int beststeps = INT_MAX;
+ struct ast_format best;
+ struct ast_format bestdst;
+ struct ast_format_cap *joint_cap = ast_format_cap_joint(dst_cap, src_cap);
+ ast_format_clear(&best);
+ ast_format_clear(&bestdst);
+
+ if (joint_cap) { /* yes, pick one and return */
+ struct ast_format tmp_fmt;
+ ast_format_cap_iter_start(joint_cap);
+ while (!ast_format_cap_iter_next(joint_cap, &tmp_fmt)) {
/* We are guaranteed to find one common format. */
- if (best == -1) {
- best = cur;
+ if (!best.id) {
+ ast_format_copy(&best, &tmp_fmt);
continue;
}
/* If there are multiple common formats, pick the one with the highest sample rate */
- if (ast_format_rate(best) < ast_format_rate(cur)) {
- best = cur;
+ if (ast_format_rate(&best) < ast_format_rate(&tmp_fmt)) {
+ ast_format_copy(&best, &tmp_fmt);
continue;
}
+
}
+ ast_format_cap_iter_end(joint_cap);
+
/* We are done, this is a common format to both. */
- *srcs = *dst = best;
+ ast_format_copy(dst_fmt_out, &best);
+ ast_format_copy(src_fmt_out, &best);
+ ast_format_cap_destroy(joint_cap);
return 0;
} else { /* No, we will need to translate */
+ struct ast_format cur_dst;
+ struct ast_format cur_src;
AST_RWLIST_RDLOCK(&translators);
- for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
- if (! (cur & *dst)) {
- continue;
- }
- for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
- if (!(*srcs & cursrc) || !tr_matrix[x][y].step) {
- continue;
- }
- /* This is a better choice if any of the following are true.
- * 1. The sample rate conversion is better than the current pick.
- * 2. the sample rate conversion is no worse than the current pick and the cost or multistep is better
- */
- better = 0;
- if (tr_matrix[x][y].rate_change < best_rate_change) {
- better = 1; /* this match has a better rate conversion */
+ ast_format_cap_iter_start(dst_cap);
+ while (!ast_format_cap_iter_next(dst_cap, &cur_dst)) {
+ ast_format_cap_iter_start(src_cap);
+ while (!ast_format_cap_iter_next(src_cap, &cur_src)) {
+ int x = format2index(cur_src.id);
+ int y = format2index(cur_dst.id);
+ if (x < 0 || y < 0) {
+ continue;
}
- if ((tr_matrix[x][y].rate_change <= best_rate_change) &&
- (tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) {
- better = 1; /* this match has no worse rate conversion and the conversion cost is less */
+ if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) {
+ continue;
}
- if (better) {
+ if (((matrix_get(x, y)->table_cost < besttablecost) || (matrix_get(x, y)->multistep < beststeps))) {
/* better than what we have so far */
- best = cursrc;
- bestdst = cur;
- besttime = tr_matrix[x][y].cost;
- beststeps = tr_matrix[x][y].multistep;
- best_rate_change = tr_matrix[x][y].rate_change;
+ ast_format_copy(&best, &cur_src);
+ ast_format_copy(&bestdst, &cur_dst);
+ besttablecost = matrix_get(x, y)->table_cost;
+ beststeps = matrix_get(x, y)->multistep;
}
}
+ ast_format_cap_iter_end(src_cap);
}
+
+ ast_format_cap_iter_end(dst_cap);
AST_RWLIST_UNLOCK(&translators);
- if (best > -1) {
- *srcs = best;
- *dst = bestdst;
- best = 0;
+ if (best.id) {
+ ast_format_copy(dst_fmt_out, &bestdst);
+ ast_format_copy(src_fmt_out, &best);
+ return 0;
}
- return best;
+ return -1;
}
}
-unsigned int ast_translate_path_steps(format_t dest, format_t src)
+unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_format *src_format)
{
unsigned int res = -1;
-
+ int src, dest;
/* convert bitwise format numbers into array indices */
- src = powerof(src);
- dest = powerof(dest);
+ src = format2index(src_format->id);
+ dest = format2index(dst_format->id);
if (src == -1 || dest == -1) {
ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
@@ -1002,97 +1242,123 @@ unsigned int ast_translate_path_steps(format_t dest, format_t src)
}
AST_RWLIST_RDLOCK(&translators);
- if (tr_matrix[src][dest].step)
- res = tr_matrix[src][dest].multistep + 1;
+ if (matrix_get(src, dest)->step) {
+ res = matrix_get(src, dest)->multistep + 1;
+ }
AST_RWLIST_UNLOCK(&translators);
return res;
}
-format_t ast_translate_available_formats(format_t dest, format_t src)
+void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_format_cap *src, struct ast_format_cap *result)
{
- format_t res = dest;
- format_t x;
- format_t src_audio = src & AST_FORMAT_AUDIO_MASK;
- format_t src_video = src & AST_FORMAT_VIDEO_MASK;
+ struct ast_format tmp_fmt;
+ struct ast_format cur_src;
+ int src_audio = 0;
+ int src_video = 0;
+ int index;
+
+ ast_format_cap_copy(result, dest);
/* if we don't have a source format, we just have to try all
possible destination formats */
- if (!src)
- return dest;
+ if (!src) {
+ return;
+ }
- /* If we have a source audio format, get its format index */
- if (src_audio)
- src_audio = powerof(src_audio);
+ ast_format_cap_iter_start(src);
+ while (!ast_format_cap_iter_next(src, &cur_src)) {
+ /* If we have a source audio format, get its format index */
+ if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_AUDIO) {
+ src_audio = format2index(cur_src.id);
+ }
- /* If we have a source video format, get its format index */
- if (src_video)
- src_video = powerof(src_video);
+ /* If we have a source video format, get its format index */
+ if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_VIDEO) {
+ src_video = format2index(cur_src.id);
+ }
- AST_RWLIST_RDLOCK(&translators);
+ AST_RWLIST_RDLOCK(&translators);
- /* For a given source audio format, traverse the list of
- known audio formats to determine whether there exists
- a translation path from the source format to the
- destination format. */
- for (x = 1LL; src_audio && x > 0; x <<= 1) {
- if (!(x & AST_FORMAT_AUDIO_MASK)) {
- continue;
- }
+ /* For a given source audio format, traverse the list of
+ known audio formats to determine whether there exists
+ a translation path from the source format to the
+ destination format. */
+ for (index = 0; (src_audio >= 0) && index < cur_max_index; index++) {
+ ast_format_set(&tmp_fmt, index2format(index), 0);
- /* if this is not a desired format, nothing to do */
- if (!(dest & x))
- continue;
+ if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) {
+ continue;
+ }
- /* if the source is supplying this format, then
- we can leave it in the result */
- if (src & x)
- continue;
+ /* if this is not a desired format, nothing to do */
+ if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
+ continue;
+ }
- /* if we don't have a translation path from the src
- to this format, remove it from the result */
- if (!tr_matrix[src_audio][powerof(x)].step) {
- res &= ~x;
- continue;
- }
+ /* if the source is supplying this format, then
+ we can leave it in the result */
+ if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
+ continue;
+ }
- /* now check the opposite direction */
- if (!tr_matrix[powerof(x)][src_audio].step)
- res &= ~x;
- }
+ /* if we don't have a translation path from the src
+ to this format, remove it from the result */
+ if (!matrix_get(src_audio, index)->step) {
+ ast_format_cap_remove_byid(result, tmp_fmt.id);
+ continue;
+ }
- /* For a given source video format, traverse the list of
- known video formats to determine whether there exists
- a translation path from the source format to the
- destination format. */
- for (x = 1LL; src_video && x > 0; x <<= 1) {
- if (!(x & AST_FORMAT_VIDEO_MASK)) {
- continue;
+ /* now check the opposite direction */
+ if (!matrix_get(index, src_audio)->step) {
+ ast_format_cap_remove_byid(result, tmp_fmt.id);
+ }
}
- /* if this is not a desired format, nothing to do */
- if (!(dest & x))
- continue;
+ /* For a given source video format, traverse the list of
+ known video formats to determine whether there exists
+ a translation path from the source format to the
+ destination format. */
+ for (index = 0; (src_video >= 0) && index < cur_max_index; index++) {
+ ast_format_set(&tmp_fmt, index2format(index), 0);
+ if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) {
+ continue;
+ }
- /* if the source is supplying this format, then
- we can leave it in the result */
- if (src & x)
- continue;
+ /* if this is not a desired format, nothing to do */
+ if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
+ continue;
+ }
- /* if we don't have a translation path from the src
- to this format, remove it from the result */
- if (!tr_matrix[src_video][powerof(x)].step) {
- res &= ~x;
- continue;
- }
+ /* if the source is supplying this format, then
+ we can leave it in the result */
+ if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
+ continue;
+ }
- /* now check the opposite direction */
- if (!tr_matrix[powerof(x)][src_video].step)
- res &= ~x;
- }
+ /* if we don't have a translation path from the src
+ to this format, remove it from the result */
+ if (!matrix_get(src_video, index)->step) {
+ ast_format_cap_remove_byid(result, tmp_fmt.id);
+ continue;
+ }
- AST_RWLIST_UNLOCK(&translators);
+ /* now check the opposite direction */
+ if (!matrix_get(index, src_video)->step) {
+ ast_format_cap_remove_byid(result, tmp_fmt.id);
+ }
+ }
+ AST_RWLIST_UNLOCK(&translators);
+ }
+ ast_format_cap_iter_end(src);
+}
+int ast_translate_init(void)
+{
+ int res = 0;
+ ast_rwlock_init(&tablelock);
+ res = matrix_resize(1);
+ res |= ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
return res;
}
diff --git a/main/udptl.c b/main/udptl.c
index 1845ca882..f5abbb900 100644
--- a/main/udptl.c
+++ b/main/udptl.c
@@ -379,7 +379,7 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
/* Decode the secondary IFP packet */
//fprintf(stderr, "Secondary %d, len %d\n", seq_no - i, lengths[i - 1]);
s->f[ifp_no].frametype = AST_FRAME_MODEM;
- s->f[ifp_no].subclass.codec = AST_MODEM_T38;
+ s->f[ifp_no].subclass.integer = AST_MODEM_T38;
s->f[ifp_no].mallocd = 0;
s->f[ifp_no].seqno = seq_no - i;
@@ -481,7 +481,7 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
if (repaired[l]) {
//fprintf(stderr, "Fixed packet %d, len %d\n", j, l);
s->f[ifp_no].frametype = AST_FRAME_MODEM;
- s->f[ifp_no].subclass.codec = AST_MODEM_T38;
+ s->f[ifp_no].subclass.integer = AST_MODEM_T38;
s->f[ifp_no].mallocd = 0;
s->f[ifp_no].seqno = j;
@@ -502,7 +502,7 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
if (seq_no >= s->rx_seq_no) {
/* Decode the primary IFP packet */
s->f[ifp_no].frametype = AST_FRAME_MODEM;
- s->f[ifp_no].subclass.codec = AST_MODEM_T38;
+ s->f[ifp_no].subclass.integer = AST_MODEM_T38;
s->f[ifp_no].mallocd = 0;
s->f[ifp_no].seqno = seq_no;
@@ -1057,7 +1057,7 @@ int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
return 0;
if ((f->frametype != AST_FRAME_MODEM) ||
- (f->subclass.codec != AST_MODEM_T38)) {
+ (f->subclass.integer != AST_MODEM_T38)) {
ast_log(LOG_WARNING, "(%s): UDPTL can only send T.38 data.\n",
LOG_TAG(s));
return -1;