menuselect: Remove ineffective weak attribute detection.
[asterisk/asterisk.git] / channels / chan_console.c
index 6c566e9..a24a6c8 100644 (file)
@@ -29,7 +29,7 @@
  * 
  * \ingroup channel_drivers
  *
- * \extref Portaudio http://www.portaudio.com/
+ * Portaudio http://www.portaudio.com/
  *
  * To install portaudio v19 from svn, check it out using the following command:
  *  - svn co https://www.portaudio.com/repos/portaudio/branches/v19-devel
  * - console_video support
  */
 
+/*! \li \ref chan_console.c uses the configuration file \ref console.conf
+ * \addtogroup configuration_file
+ */
+
+/*! \page console.conf console.conf
+ * \verbinclude console.conf.sample
+ */
+
 /*** MODULEINFO
        <depend>portaudio</depend>
+       <support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <sys/signal.h>  /* SIGURG */
+#include <signal.h>  /* SIGURG */
 
 #include <portaudio.h>
 
@@ -67,6 +74,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/musiconhold.h"
 #include "asterisk/callerid.h"
 #include "asterisk/astobj2.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/format_cache.h"
 
 /*! 
  * \brief The sample rate to request from PortAudio 
@@ -172,41 +181,36 @@ AST_RWLOCK_DEFINE_STATIC(active_lock);
  * \brief Global jitterbuffer configuration 
  *
  * \note Disabled by default.
+ * \note Values shown here match the defaults shown in console.conf.sample
  */
 static struct ast_jb_conf default_jbconf = {
        .flags = 0,
-       .max_size = -1,
-       .resync_threshold = -1,
-       .impl = "",
-       .target_extra = -1,
+       .max_size = 200,
+       .resync_threshold = 1000,
+       .impl = "fixed",
+       .target_extra = 40,
 };
 static struct ast_jb_conf global_jbconf;
 
 /*! Channel Technology Callbacks @{ */
-static struct ast_channel *console_request(const char *type, format_t format,
-       const struct ast_channel *requestor, void *data, int *cause);
+static struct ast_channel *console_request(const char *type, struct ast_format_cap *cap,
+       const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
 static int console_digit_begin(struct ast_channel *c, char digit);
 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration);
 static int console_text(struct ast_channel *c, const char *text);
 static int console_hangup(struct ast_channel *c);
 static int console_answer(struct ast_channel *c);
 static struct ast_frame *console_read(struct ast_channel *chan);
-static int console_call(struct ast_channel *c, char *dest, int timeout);
+static int console_call(struct ast_channel *c, const char *dest, int timeout);
 static int console_write(struct ast_channel *chan, struct ast_frame *f);
 static int console_indicate(struct ast_channel *chan, int cond, 
        const void *data, size_t datalen);
 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 /*! @} */
 
-/*!
- * \brief Formats natively supported by this module.
- */
-#define SUPPORTED_FORMATS ( AST_FORMAT_SLINEAR16 )
-
-static const struct ast_channel_tech console_tech = {
+static struct ast_channel_tech console_tech = {
        .type = "Console",
        .description = "Console Channel Driver",
-       .capabilities = SUPPORTED_FORMATS,
        .requester = console_request,
        .send_digit_begin = console_digit_begin,
        .send_digit_end = console_digit_end,
@@ -265,7 +269,7 @@ static void *stream_monitor(void *data)
        PaError res;
        struct ast_frame f = {
                .frametype = AST_FRAME_VOICE,
-               .subclass.codec = AST_FORMAT_SLINEAR16,
+               .subclass.format = ast_format_slin16,
                .src = "console_stream_monitor",
                .data.ptr = buf,
                .datalen = sizeof(buf),
@@ -414,31 +418,45 @@ static int stop_stream(struct console_pvt *pvt)
 /*!
  * \note Called with the pvt struct locked
  */
-static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const char *linkedid)
+static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
 {
+       struct ast_format_cap *caps;
        struct ast_channel *chan;
 
+       caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+       if (!caps) {
+               return NULL;
+       }
+
        if (!(chan = ast_channel_alloc(1, state, pvt->cid_num, pvt->cid_name, NULL, 
-               ext, ctx, linkedid, 0, "Console/%s", pvt->name))) {
+               ext, ctx, assignedids, requestor, 0, "Console/%s", pvt->name))) {
+               ao2_ref(caps, -1);
                return NULL;
        }
 
-       chan->tech = &console_tech;
-       chan->nativeformats = AST_FORMAT_SLINEAR16;
-       chan->readformat = AST_FORMAT_SLINEAR16;
-       chan->writeformat = AST_FORMAT_SLINEAR16;
-       chan->tech_pvt = ref_pvt(pvt);
+       ast_channel_stage_snapshot(chan);
+
+       ast_channel_tech_set(chan, &console_tech);
+       ast_channel_set_readformat(chan, ast_format_slin16);
+       ast_channel_set_writeformat(chan, ast_format_slin16);
+       ast_format_cap_append(caps, ast_format_slin16, 0);
+       ast_channel_nativeformats_set(chan, caps);
+       ao2_ref(caps, -1);
+       ast_channel_tech_pvt_set(chan, ref_pvt(pvt));
 
        pvt->owner = chan;
 
        if (!ast_strlen_zero(pvt->language))
-               ast_string_field_set(chan, language, pvt->language);
+               ast_channel_language_set(chan, pvt->language);
 
        ast_jb_configure(chan, &global_jbconf);
 
+       ast_channel_stage_snapshot_done(chan);
+       ast_channel_unlock(chan);
+
        if (state != AST_STATE_DOWN) {
                if (ast_pbx_start(chan)) {
-                       chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+                       ast_channel_hangupcause_set(chan, AST_CAUSE_SWITCH_CONGESTION);
                        ast_hangup(chan);
                        chan = NULL;
                } else
@@ -448,21 +466,20 @@ static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext,
        return chan;
 }
 
-static struct ast_channel *console_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
+static struct ast_channel *console_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
 {
-       format_t oldformat = format;
        struct ast_channel *chan = NULL;
        struct console_pvt *pvt;
-       char buf[512];
 
        if (!(pvt = find_pvt(data))) {
-               ast_log(LOG_ERROR, "Console device '%s' not found\n", (char *) data);
+               ast_log(LOG_ERROR, "Console device '%s' not found\n", data);
                return NULL;
        }
 
-       format &= SUPPORTED_FORMATS;
-       if (!format) {
-               ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), oldformat));
+       if (!(ast_format_cap_iscompatible(cap, console_tech.capabilities))) {
+               struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n",
+                       ast_format_cap_get_names(cap, &cap_buf));
                goto return_unref;
        }
 
@@ -473,7 +490,7 @@ static struct ast_channel *console_request(const char *type, format_t format, co
        }
 
        console_pvt_lock(pvt);
-       chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
+       chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN, assignedids, requestor);
        console_pvt_unlock(pvt);
 
        if (!chan)
@@ -509,7 +526,7 @@ static int console_text(struct ast_channel *c, const char *text)
 
 static int console_hangup(struct ast_channel *c)
 {
-       struct console_pvt *pvt = c->tech_pvt;
+       struct console_pvt *pvt = ast_channel_tech_pvt(c);
 
        ast_verb(1, V_BEGIN "Hangup on Console" V_END);
 
@@ -517,14 +534,14 @@ static int console_hangup(struct ast_channel *c)
        pvt->owner = NULL;
        stop_stream(pvt);
 
-       c->tech_pvt = unref_pvt(pvt);
+       ast_channel_tech_pvt_set(c, unref_pvt(pvt));
 
        return 0;
 }
 
 static int console_answer(struct ast_channel *c)
 {
-       struct console_pvt *pvt = c->tech_pvt;
+       struct console_pvt *pvt = ast_channel_tech_pvt(c);
 
        ast_verb(1, V_BEGIN "Call from Console has been Answered" V_END);
 
@@ -560,13 +577,15 @@ static struct ast_frame *console_read(struct ast_channel *chan)
        return &ast_null_frame;
 }
 
-static int console_call(struct ast_channel *c, char *dest, int timeout)
+static int console_call(struct ast_channel *c, const char *dest, int timeout)
 {
-       struct console_pvt *pvt = c->tech_pvt;
+       struct console_pvt *pvt = ast_channel_tech_pvt(c);
        enum ast_control_frame_type ctrl;
 
        ast_verb(1, V_BEGIN "Call to device '%s' on console from '%s' <%s>" V_END,
-               dest, c->cid.cid_name, c->cid.cid_num);
+               dest,
+               S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, ""),
+               S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""));
 
        console_pvt_lock(pvt);
 
@@ -590,7 +609,7 @@ static int console_call(struct ast_channel *c, char *dest, int timeout)
 
 static int console_write(struct ast_channel *chan, struct ast_frame *f)
 {
-       struct console_pvt *pvt = chan->tech_pvt;
+       struct console_pvt *pvt = ast_channel_tech_pvt(chan);
 
        Pa_WriteStream(pvt->stream, f->data.ptr, f->samples);
 
@@ -599,13 +618,15 @@ static int console_write(struct ast_channel *chan, struct ast_frame *f)
 
 static int console_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
 {
-       struct console_pvt *pvt = chan->tech_pvt;
+       struct console_pvt *pvt = ast_channel_tech_pvt(chan);
        int res = 0;
 
        switch (cond) {
        case AST_CONTROL_BUSY:
        case AST_CONTROL_CONGESTION:
        case AST_CONTROL_RINGING:
+       case AST_CONTROL_INCOMPLETE:
+       case AST_CONTROL_PVT_CAUSE_CODE:
        case -1:
                res = -1;  /* Ask for inband indications */
                break;
@@ -624,7 +645,7 @@ static int console_indicate(struct ast_channel *chan, int cond, const void *data
                break;
        default:
                ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", 
-                       cond, chan->name);
+                       cond, ast_channel_name(chan));
                /* The core will play inband indications for us if appropriate */
                res = -1;
        }
@@ -634,7 +655,7 @@ static int console_indicate(struct ast_channel *chan, int cond, const void *data
 
 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
-       struct console_pvt *pvt = newchan->tech_pvt;
+       struct console_pvt *pvt = ast_channel_tech_pvt(newchan);
 
        pvt->owner = newchan;
 
@@ -689,7 +710,7 @@ static struct console_pvt *get_active_pvt(void)
 static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd, 
        struct ast_cli_args *a)
 {
-       struct console_pvt *pvt = get_active_pvt();
+       struct console_pvt *pvt;
        char *res = CLI_SUCCESS;
 
        switch (cmd) {
@@ -706,6 +727,7 @@ static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd,
                return NULL;
        }
 
+       pvt = get_active_pvt();
        if (!pvt) {
                ast_cli(a->fd, "No console device is set as active.\n");
                return CLI_FAILURE;
@@ -731,12 +753,12 @@ static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd,
 
        unref_pvt(pvt);
 
-       return CLI_SUCCESS;
+       return res;
 }
 
 static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       struct console_pvt *pvt = get_active_pvt();
+       struct console_pvt *pvt;
 
        if (cmd == CLI_INIT) {
                e->command = "console flash";
@@ -744,17 +766,20 @@ static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_
                        "Usage: console flash\n"
                        "       Flashes the call currently placed on the console.\n";
                return NULL;
-       } else if (cmd == CLI_GENERATE)
+       } else if (cmd == CLI_GENERATE) {
                return NULL;
+       }
+
+       if (a->argc != e->args) {
+               return CLI_SHOWUSAGE;
+       }
 
+       pvt = get_active_pvt();
        if (!pvt) {
                ast_cli(a->fd, "No console device is set as active\n");
                return CLI_FAILURE;
        }
 
-       if (a->argc != e->args)
-               return CLI_SHOWUSAGE;
-
        if (!pvt->owner) {
                ast_cli(a->fd, "No call to flash\n");
                unref_pvt(pvt);
@@ -774,7 +799,7 @@ static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 {
        char *s = NULL;
        const char *mye = NULL, *myc = NULL; 
-       struct console_pvt *pvt = get_active_pvt();
+       struct console_pvt *pvt;
 
        if (cmd == CLI_INIT) {
                e->command = "console dial";
@@ -782,16 +807,19 @@ static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                        "Usage: console dial [extension[@context]]\n"
                        "       Dials a given extension (and context if specified)\n";
                return NULL;
-       } else if (cmd == CLI_GENERATE)
+       } else if (cmd == CLI_GENERATE) {
                return NULL;
+       }
+
+       if (a->argc > e->args + 1) {
+               return CLI_SHOWUSAGE;
+       }
 
+       pvt = get_active_pvt();
        if (!pvt) {
                ast_cli(a->fd, "No console device is currently set as active\n");
                return CLI_FAILURE;
        }
-       
-       if (a->argc > e->args + 1)
-               return CLI_SHOWUSAGE;
 
        if (pvt->owner) {       /* already in a call */
                int i;
@@ -832,12 +860,12 @@ static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_a
        if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
                console_pvt_lock(pvt);
                pvt->hookstate = 1;
-               console_new(pvt, mye, myc, AST_STATE_RINGING, NULL);
+               console_new(pvt, mye, myc, AST_STATE_RINGING, NULL, NULL);
                console_pvt_unlock(pvt);
        } else
                ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
 
-       free(s);
+       ast_free(s);
 
        unref_pvt(pvt);
 
@@ -846,7 +874,7 @@ static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 
 static char *cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       struct console_pvt *pvt = get_active_pvt();
+       struct console_pvt *pvt;
 
        if (cmd == CLI_INIT) {
                e->command = "console hangup";
@@ -854,16 +882,19 @@ static char *cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli
                        "Usage: console hangup\n"
                        "       Hangs up any call currently placed on the console.\n";
                return NULL;
-       } else if (cmd == CLI_GENERATE)
+       } else if (cmd == CLI_GENERATE) {
                return NULL;
+       }
+
+       if (a->argc != e->args) {
+               return CLI_SHOWUSAGE;
+       }
 
+       pvt = get_active_pvt();
        if (!pvt) {
                ast_cli(a->fd, "No console device is set as active\n");
                return CLI_FAILURE;
        }
-       
-       if (a->argc != e->args)
-               return CLI_SHOWUSAGE;
 
        if (!pvt->owner && !pvt->hookstate) {
                ast_cli(a->fd, "No call to hang up\n");
@@ -883,7 +914,7 @@ static char *cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli
 static char *cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        const char *s;
-       struct console_pvt *pvt = get_active_pvt();
+       struct console_pvt *pvt;
        char *res = CLI_SUCCESS;
 
        if (cmd == CLI_INIT) {
@@ -892,17 +923,20 @@ static char *cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                        "Usage: console {mute|unmute}\n"
                        "       Mute/unmute the microphone.\n";
                return NULL;
-       } else if (cmd == CLI_GENERATE)
+       } else if (cmd == CLI_GENERATE) {
                return NULL;
+       }
 
+       if (a->argc != e->args) {
+               return CLI_SHOWUSAGE;
+       }
+
+       pvt = get_active_pvt();
        if (!pvt) {
                ast_cli(a->fd, "No console device is set as active\n");
                return CLI_FAILURE;
        }
 
-       if (a->argc != e->args)
-               return CLI_SHOWUSAGE;
-
        s = a->argv[e->args-1];
        if (!strcasecmp(s, "mute"))
                pvt->muted = 1;
@@ -1030,7 +1064,7 @@ static char *cli_list_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_a
  */
 static char *cli_console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       struct console_pvt *pvt = get_active_pvt();
+       struct console_pvt *pvt;
 
        switch (cmd) {
        case CLI_INIT:
@@ -1044,6 +1078,7 @@ static char *cli_console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli
                return NULL;    /* no completion */
        }
 
+       pvt = get_active_pvt();
        if (!pvt) {
                ast_cli(a->fd, "No console device is set as active\n");
                return CLI_FAILURE;
@@ -1080,7 +1115,7 @@ static char *cli_console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli
 static char *cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        char buf[TEXT_SIZE];
-       struct console_pvt *pvt = get_active_pvt();
+       struct console_pvt *pvt;
        struct ast_frame f = {
                .frametype = AST_FRAME_TEXT,
                .data.ptr = buf,
@@ -1094,9 +1129,11 @@ static char *cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_c
                        "Usage: console send text <message>\n"
                        "       Sends a text message for display on the remote terminal.\n";
                return NULL;
-       } else if (cmd == CLI_GENERATE)
+       } else if (cmd == CLI_GENERATE) {
                return NULL;
+       }
 
+       pvt = get_active_pvt();
        if (!pvt) {
                ast_cli(a->fd, "No console device is set as active\n");
                return CLI_FAILURE;
@@ -1153,7 +1190,7 @@ static char *cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli
 
        switch (cmd) {
        case CLI_INIT:
-               e->command = "console {set|show} active [<device>]";
+               e->command = "console {set|show} active";
                e->usage =
                        "Usage: console {set|show} active [<device>]\n"
                        "       Set or show the active console device for the Asterisk CLI.\n";
@@ -1196,7 +1233,7 @@ static char *cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli
                return CLI_SUCCESS;
        }
 
-       if (!(pvt = find_pvt(a->argv[e->args]))) {
+       if (!(pvt = find_pvt(a->argv[e->args - 1]))) {
                ast_cli(a->fd, "Could not find a device called '%s'.\n", a->argv[e->args]);
                return CLI_FAILURE;
        }
@@ -1455,6 +1492,8 @@ static void stop_streams(void)
 
 static int unload_module(void)
 {
+       ao2_ref(console_tech.capabilities, -1);
+       console_tech.capabilities = NULL;
        ast_channel_unregister(&console_tech);
        ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
 
@@ -1470,10 +1509,25 @@ static int unload_module(void)
        return 0;
 }
 
+/*!
+ * \brief Load the module
+ *
+ * Module loading including tests for configuration or dependencies.
+ * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
+ * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
+ * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
+ * configuration file or other non-critical problem return 
+ * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
+ */
 static int load_module(void)
 {
        PaError res;
 
+       if (!(console_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+               return AST_MODULE_LOAD_DECLINE;
+       }
+       ast_format_cap_append(console_tech.capabilities, ast_format_slin16, 0);
+
        init_pvt(&globals, NULL);
 
        if (!(pvts = ao2_container_alloc(NUM_PVT_BUCKETS, pvt_hash_cb, pvt_cmp_cb)))
@@ -1509,6 +1563,8 @@ return_error:
        if (pvts)
                ao2_ref(pvts, -1);
        pvts = NULL;
+       ao2_ref(console_tech.capabilities, -1);
+       console_tech.capabilities = NULL;
        pvt_destructor(&globals);
 
        return AST_MODULE_LOAD_DECLINE;
@@ -1519,8 +1575,10 @@ static int reload(void)
        return load_config(1);
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Console Channel Driver",
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Console Channel Driver",
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
 );