Add support for allowing the channel driver to handle transcoding.
authorJoshua Colp <jcolp@digium.com>
Thu, 9 Apr 2009 16:19:35 +0000 (16:19 +0000)
committerJoshua Colp <jcolp@digium.com>
Thu, 9 Apr 2009 16:19:35 +0000 (16:19 +0000)
This was accomplished using a set of options and the setoption channel callback.
The core calls into the channel driver using these options and the channel driver
either returns success or failure.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@187360 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
include/asterisk/frame.h
main/channel.c

index c3f62d8..c255f5e 100644 (file)
@@ -2272,6 +2272,7 @@ static int sip_transfer(struct ast_channel *ast, const char *dest);
 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);
 
@@ -2680,6 +2681,7 @@ static const struct ast_channel_tech sip_tech = {
        .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,
 };
@@ -3924,6 +3926,26 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp
        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)
 {
index f7e8b20..a16cf80 100644 (file)
@@ -391,6 +391,15 @@ enum ast_control_transfer {
  */
 #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;
index acf3f55..f3444ea 100644 (file)
@@ -3769,7 +3769,7 @@ done:
 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];
        
@@ -3780,7 +3780,19 @@ static int set_format(struct ast_channel *chan, int fmt, int *rawformat, int *fo
 
        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 */
@@ -4202,6 +4214,12 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
        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;