static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
static int sip_senddigit_begin(struct ast_channel *ast, char digit);
static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
+static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen);
static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
static const char *sip_get_callid(struct ast_channel *chan);
.early_bridge = ast_rtp_instance_early_bridge,
.send_text = sip_sendtext, /* called with chan locked */
.func_channel_read = acf_channel_read,
+ .setoption = sip_setoption,
.queryoption = sip_queryoption,
.get_pvt_uniqueid = sip_get_callid,
};
return res;
}
+/*! \brief Set an option on a SIP dialog */
+static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen)
+{
+ int res = -1;
+ struct sip_pvt *p = chan->tech_pvt;
+
+ if (option == AST_OPTION_FORMAT_READ) {
+ int format = *(int *)data;
+ res = ast_rtp_instance_set_read_format(p->rtp, format);
+ } else if (option == AST_OPTION_FORMAT_WRITE) {
+ int format = *(int *)data;
+ res = ast_rtp_instance_set_write_format(p->rtp, format);
+ } else if (option == AST_OPTION_MAKE_COMPATIBLE) {
+ struct ast_channel *peer = data;
+ res = ast_rtp_instance_make_compatible(chan, p->rtp, peer);
+ }
+
+ return res;
+}
+
/*! \brief Query an option on a SIP dialog */
static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
{
*/
#define AST_OPTION_T38_STATE 10
+/*! Request that the channel driver deliver frames in a specific format */
+#define AST_OPTION_FORMAT_READ 11
+
+/*! Request that the channel driver be prepared to accept frames in a specific format */
+#define AST_OPTION_FORMAT_WRITE 12
+
+/*! Request that the channel driver make two channels of the same tech type compatible if possible */
+#define AST_OPTION_MAKE_COMPATIBLE 13
+
struct oprmode {
struct ast_channel *peer;
int mode;
static int set_format(struct ast_channel *chan, int fmt, int *rawformat, int *format,
struct ast_trans_pvt **trans, const int direction)
{
- int native;
+ int native, native_fmt = ast_best_codec(fmt);
int res;
char from[200], to[200];
if (!fmt || !native) /* No audio requested */
return 0; /* Let's try a call without any sounds (video, text) */
-
+
+ /* 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)) {
+ ast_debug(1, "Channel driver natively set channel %s to %s format %s (%d)\n", chan->name,
+ direction ? "write" : "read", ast_getformatname(native_fmt), native_fmt);
+ chan->nativeformats = *rawformat = *format = native_fmt;
+ if (*trans) {
+ ast_translator_free_path(*trans);
+ }
+ *trans = NULL;
+ return 0;
+ }
+
/* Find a translation path from the native format to one of the desired formats */
if (!direction)
/* reading */
int src;
int dst;
+ /* See if the channel driver can natively make these two channels compatible */
+ if (from->tech->bridge && from->tech->bridge == to->tech->bridge &&
+ !ast_channel_setoption(from, AST_OPTION_MAKE_COMPATIBLE, to, sizeof(struct ast_channel *), 0)) {
+ return 0;
+ }
+
if (from->readformat == to->writeformat && from->writeformat == to->readformat) {
/* Already compatible! Moving on ... */
return 0;