summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
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;