memory leaks: Memory leak cleanup patch by Corey Farrell (second set)
[asterisk/asterisk.git] / channels / chan_dahdi.c
index 5fc9683..b682994 100644 (file)
@@ -553,7 +553,7 @@ static int restart_monitor(void);
 
 static int dahdi_sendtext(struct ast_channel *c, const char *text);
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *msg)
+static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 {
        /* This module does not handle MWI in an event-based manner.  However, it
         * subscribes to MWI for each mailbox that is configured so that the core
@@ -4526,6 +4526,15 @@ void dahdi_ec_disable(struct dahdi_pvt *p)
        p->echocanon = 0;
 }
 
+static int set_hwgain(int fd, float gain, int tx_direction)
+{
+       struct dahdi_hwgain hwgain;
+
+       hwgain.newgain = gain * 10.0;
+       hwgain.tx = tx_direction;
+       return ioctl(fd, DAHDI_SET_HWGAIN, &hwgain) < 0;
+}
+
 /* perform a dynamic range compression transform on the given sample */
 static int drc_sample(int sample, float drc)
 {
@@ -8910,6 +8919,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
                return NULL;
        }
 
+       ast_channel_stage_snapshot(tmp);
+
        if (callid) {
                ast_channel_callid_set(tmp, callid);
        }
@@ -9087,6 +9098,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
        for (v = i->vars ; v ; v = v->next)
                pbx_builtin_setvar_helper(tmp, v->name, v->value);
 
+       ast_channel_stage_snapshot_done(tmp);
+
        ast_module_ref(ast_module_info->self);
 
        dahdi_ami_channel_event(i, tmp);
@@ -9722,16 +9735,34 @@ static void *analog_ss_thread(void *data)
                                getforward = 0;
                                memset(exten, 0, sizeof(exten));
                                len = 0;
-                       } else if ((p->transfer || p->canpark) && is_exten_parking &&
-                                               p->subs[SUB_THREEWAY].owner) {
-                               RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-                               /* This is a three way call, the main call being a real channel,
-                                       and we're parking the first call. */
-                               ast_channel_lock(chan);
-                               bridge_channel = ast_channel_get_bridge_channel(chan);
-                               ast_channel_unlock(chan);
-                               if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
-                                       ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+                       } else if ((p->transfer || p->canpark) && is_exten_parking
+                               && p->subs[SUB_THREEWAY].owner) {
+                               struct ast_bridge_channel *bridge_channel;
+
+                               /*
+                                * This is a three way call, the main call being a real channel,
+                                * and we're parking the first call.
+                                */
+                               ast_channel_lock(p->subs[SUB_THREEWAY].owner);
+                               bridge_channel = ast_channel_get_bridge_channel(p->subs[SUB_THREEWAY].owner);
+                               ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+                               if (bridge_channel) {
+                                       if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+                                               /*
+                                                * Swap things around between the three-way and real call so we
+                                                * can hear where the channel got parked.
+                                                */
+                                               ast_mutex_lock(&p->lock);
+                                               p->owner = p->subs[SUB_THREEWAY].owner;
+                                               swap_subs(p, SUB_THREEWAY, SUB_REAL);
+                                               ast_mutex_unlock(&p->lock);
+
+                                               ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
+                                               ast_hangup(chan);
+                                               ao2_ref(bridge_channel, -1);
+                                               goto quit;
+                                       }
+                                       ao2_ref(bridge_channel, -1);
                                }
                                break;
                        } else if (p->hidecallerid && !strcmp(exten, "*82")) {
@@ -11124,6 +11155,11 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
        return NULL;
 }
 
+static void monitor_pfds_clean(void *arg) {
+       struct pollfd **pfds = arg;
+       ast_free(*pfds);
+}
+
 static void *do_monitor(void *data)
 {
        int count, res, res2, spoint, pollres=0;
@@ -11147,6 +11183,7 @@ static void *do_monitor(void *data)
 #endif
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 
+       pthread_cleanup_push(monitor_pfds_clean, &pfds);
        for (;;) {
                /* Lock the interface list */
                ast_mutex_lock(&iflock);
@@ -11402,6 +11439,7 @@ static void *do_monitor(void *data)
                ast_mutex_unlock(&iflock);
        }
        /* Never reached */
+       pthread_cleanup_pop(1);
        return NULL;
 
 }
@@ -12429,6 +12467,10 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                }
                        }
                }
+               tmp->hwrxgain_enabled = conf->chan.hwrxgain_enabled;
+               tmp->hwtxgain_enabled = conf->chan.hwtxgain_enabled;
+               tmp->hwrxgain = conf->chan.hwrxgain;
+               tmp->hwtxgain = conf->chan.hwtxgain;
                tmp->cid_rxgain = conf->chan.cid_rxgain;
                tmp->rxgain = conf->chan.rxgain;
                tmp->txgain = conf->chan.txgain;
@@ -12436,6 +12478,12 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                tmp->rxdrc = conf->chan.rxdrc;
                tmp->tonezone = conf->chan.tonezone;
                if (tmp->subs[SUB_REAL].dfd > -1) {
+                       if (tmp->hwrxgain_enabled) {
+                               tmp->hwrxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwrxgain, 0);
+                       }
+                       if (tmp->hwtxgain_enabled) {
+                               tmp->hwtxgain_enabled = !set_hwgain(tmp->subs[SUB_REAL].dfd, tmp->hwtxgain, 1);
+                       }
                        set_actual_gain(tmp->subs[SUB_REAL].dfd, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law);
                        if (tmp->dsp)
                                ast_dsp_set_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
@@ -14988,6 +15036,8 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
        struct dahdi_confinfo ci;
        struct dahdi_params ps;
        int x;
+       char hwrxgain[15];
+       char hwtxgain[15];
 
        switch (cmd) {
        case CLI_INIT:
@@ -15061,7 +15111,18 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
                        ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
                        ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
                        ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
-                       ast_cli(a->fd, "Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
+                       if (tmp->hwrxgain_enabled) {
+                               snprintf(hwrxgain, sizeof(hwrxgain), "%.1f", tmp->hwrxgain);
+                       } else {
+                               ast_copy_string(hwrxgain, "Disabled", sizeof(hwrxgain));
+                       }
+                       if (tmp->hwtxgain_enabled) {
+                               snprintf(hwtxgain, sizeof(hwtxgain), "%.1f", tmp->hwtxgain);
+                       } else {
+                               ast_copy_string(hwtxgain, "Disabled", sizeof(hwtxgain));
+                       }
+                       ast_cli(a->fd, "HW Gains (RX/TX): %s/%s\n", hwrxgain, hwtxgain);
+                       ast_cli(a->fd, "SW Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
                        ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc);
                        ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no");
                        ast_cli(a->fd, "Echo Cancellation:\n");
@@ -15327,22 +15388,26 @@ static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli
 static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        int channel;
-       int gain;
+       float gain;
        int tx;
-       struct dahdi_hwgain hwgain;
        struct dahdi_pvt *tmp = NULL;
 
        switch (cmd) {
        case CLI_INIT:
-               e->command = "dahdi set hwgain";
+               e->command = "dahdi set hwgain {rx|tx}";
                e->usage =
                        "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
-                       "       Sets the hardware gain on a a given channel, overriding the\n"
-                       "   value provided at module loadtime, whether the channel is in\n"
-                       "   use or not.  Changes take effect immediately.\n"
+                       "   Sets the hardware gain on a given channel and overrides the\n"
+                       "   value provided at module loadtime.  Changes take effect\n"
+                       "   immediately whether the channel is in use or not.\n"
+                       "\n"
                        "   <rx|tx> which direction do you want to change (relative to our module)\n"
                        "   <chan num> is the channel number relative to the device\n"
-                       "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
+                       "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n"
+                       "\n"
+                       "   Please note:\n"
+                       "   * hwgain is only supportable by hardware with analog ports because\n"
+                       "     hwgain works on the analog side of an analog-digital conversion.\n";
                return NULL;
        case CLI_GENERATE:
                return NULL;
@@ -15359,7 +15424,7 @@ static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                return CLI_SHOWUSAGE;
 
        channel = atoi(a->argv[4]);
-       gain = atof(a->argv[5])*10.0;
+       gain = atof(a->argv[5]);
 
        ast_mutex_lock(&iflock);
 
@@ -15371,15 +15436,21 @@ static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                if (tmp->subs[SUB_REAL].dfd == -1)
                        break;
 
-               hwgain.newgain = gain;
-               hwgain.tx = tx;
-               if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_HWGAIN, &hwgain) < 0) {
+               if (set_hwgain(tmp->subs[SUB_REAL].dfd, gain, tx)) {
                        ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
                        ast_mutex_unlock(&iflock);
                        return CLI_FAILURE;
                }
-               ast_cli(a->fd, "hardware %s gain set to %d (%.1f dB) on channel %d\n",
-                       tx ? "tx" : "rx", gain, (float)gain/10.0, channel);
+               ast_cli(a->fd, "Hardware %s gain set to %.1f dB on channel %d.\n",
+                       tx ? "tx" : "rx", gain, channel);
+
+               if (tx) {
+                       tmp->hwtxgain_enabled = 1;
+                       tmp->hwtxgain = gain;
+               } else {
+                       tmp->hwrxgain_enabled = 1;
+                       tmp->hwrxgain = gain;
+               }
                break;
        }
 
@@ -15403,12 +15474,13 @@ static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 
        switch (cmd) {
        case CLI_INIT:
-               e->command = "dahdi set swgain";
+               e->command = "dahdi set swgain {rx|tx}";
                e->usage =
                        "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
-                       "       Sets the software gain on a a given channel, overriding the\n"
-                       "   value provided at module loadtime, whether the channel is in\n"
-                       "   use or not.  Changes take effect immediately.\n"
+                       "   Sets the software gain on a given channel and overrides the\n"
+                       "   value provided at module loadtime.  Changes take effect\n"
+                       "   immediately whether the channel is in use or not.\n"
+                       "\n"
                        "   <rx|tx> which direction do you want to change (relative to our module)\n"
                        "   <chan num> is the channel number relative to the device\n"
                        "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
@@ -15450,8 +15522,14 @@ static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                        return CLI_FAILURE;
                }
 
-               ast_cli(a->fd, "software %s gain set to %.1f on channel %d\n",
+               ast_cli(a->fd, "Software %s gain set to %.2f dB on channel %d.\n",
                        tx ? "tx" : "rx", gain, channel);
+
+               if (tx) {
+                       tmp->txgain = gain;
+               } else {
+                       tmp->rxgain = gain;
+               }
                break;
        }
        ast_mutex_unlock(&iflock);
@@ -17048,6 +17126,24 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                        if (ast_true(v->value)) {
                                confp->chan.mwimonitor_fsk = 1;
                        }
+               } else if (!strcasecmp(v->name, "hwrxgain")) {
+                       confp->chan.hwrxgain_enabled = 0;
+                       if (strcasecmp(v->value, "disabled")) {
+                               if (sscanf(v->value, "%30f", &confp->chan.hwrxgain) == 1) {
+                                       confp->chan.hwrxgain_enabled = 1;
+                               } else {
+                                       ast_log(LOG_WARNING, "Invalid hwrxgain: %s at line %d.\n", v->value, v->lineno);
+                               }
+                       }
+               } else if (!strcasecmp(v->name, "hwtxgain")) {
+                       confp->chan.hwtxgain_enabled = 0;
+                       if (strcasecmp(v->value, "disabled")) {
+                               if (sscanf(v->value, "%30f", &confp->chan.hwtxgain) == 1) {
+                                       confp->chan.hwtxgain_enabled = 1;
+                               } else {
+                                       ast_log(LOG_WARNING, "Invalid hwtxgain: %s at line %d.\n", v->value, v->lineno);
+                               }
+                       }
                } else if (!strcasecmp(v->name, "cid_rxgain")) {
                        if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
                                ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
@@ -18528,7 +18624,7 @@ static int load_module(void)
                return AST_MODULE_LOAD_FAILURE;
        }
 
-       if (!(dahdi_tech.capabilities = ast_format_cap_alloc())) {
+       if (!(dahdi_tech.capabilities = ast_format_cap_alloc(0))) {
                return AST_MODULE_LOAD_FAILURE;
        }
        ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));