Make --with-pjproject-bundled the default for Asterisk 15
[asterisk/asterisk.git] / channels / chan_oss.c
index 17894ab..ec112de 100644 (file)
  * \author Mark Spencer <markster@digium.com>
  * \author Luigi Rizzo
  *
- * \par See also
- * \arg \ref Config_oss
- *
  * \ingroup channel_drivers
  */
 
+/*! \li \ref chan_oss.c uses the configuration file \ref oss.conf
+ * \addtogroup configuration_file
+ */
+
+/*! \page oss.conf oss.conf
+ * \verbinclude oss.conf.sample
+ */
+
 /*** MODULEINFO
        <depend>oss</depend>
        <support_level>extended</support_level>
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include <ctype.h>             /* isalnum() used here */
 #include <math.h>
 #include <sys/ioctl.h>         
 
 #ifdef __linux
 #include <linux/soundcard.h>
-#elif defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__GLIBC__)
+#elif defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__GLIBC__) || defined(__sun)
 #include <sys/soundcard.h>
 #else
 #include <soundcard.h>
@@ -63,6 +66,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/causes.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/app.h"
+#include "asterisk/bridge.h"
+#include "asterisk/format_cache.h"
 
 #include "console_video.h"
 
@@ -308,7 +313,7 @@ static char *oss_active;     /*!< the active device */
 /*! \brief return the pointer to the video descriptor */
 struct video_desc *get_video_desc(struct ast_channel *c)
 {
-       struct chan_oss_pvt *o = c ? c->tech_pvt : find_desc(oss_active);
+       struct chan_oss_pvt *o = c ? ast_channel_tech_pvt(c) : find_desc(oss_active);
        return o ? o->env : NULL;
 }
 static struct chan_oss_pvt oss_default = {
@@ -328,15 +333,15 @@ static struct chan_oss_pvt oss_default = {
 
 static int setformat(struct chan_oss_pvt *o, int mode);
 
-static struct ast_channel *oss_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor,
-                                                                          void *data, int *cause);
+static struct ast_channel *oss_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 oss_digit_begin(struct ast_channel *c, char digit);
 static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration);
 static int oss_text(struct ast_channel *c, const char *text);
 static int oss_hangup(struct ast_channel *c);
 static int oss_answer(struct ast_channel *c);
 static struct ast_frame *oss_read(struct ast_channel *chan);
-static int oss_call(struct ast_channel *c, char *dest, int timeout);
+static int oss_call(struct ast_channel *c, const char *dest, int timeout);
 static int oss_write(struct ast_channel *chan, struct ast_frame *f);
 static int oss_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
@@ -531,7 +536,7 @@ static int setformat(struct chan_oss_pvt *o, int mode)
        res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
 
        if (res < 0) {
-               ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
+               ast_log(LOG_WARNING, "Failed to set sample rate to %d\n", desired);
                return -1;
        }
        if (fmt != desired) {
@@ -590,9 +595,9 @@ static int oss_text(struct ast_channel *c, const char *text)
 /*!
  * \brief handler for incoming calls. Either autoanswer, or start ringing
  */
-static int oss_call(struct ast_channel *c, char *dest, int timeout)
+static int oss_call(struct ast_channel *c, const char *dest, int timeout)
 {
-       struct chan_oss_pvt *o = c->tech_pvt;
+       struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
        struct ast_frame f = { AST_FRAME_CONTROL, };
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(name);
@@ -604,10 +609,10 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
 
        ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n",
                dest,
-               S_OR(c->dialed.number.str, ""),
-               S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, ""),
-               S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
-               S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""));
+               S_OR(ast_channel_dialed(c)->number.str, ""),
+               S_COR(ast_channel_redirecting(c)->from.number.valid, ast_channel_redirecting(c)->from.number.str, ""),
+               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, ""));
        if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "answer") == 0) {
                f.subclass.integer = AST_CONTROL_ANSWER;
                ast_queue_frame(c, &f);
@@ -634,7 +639,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout)
  */
 static int oss_answer(struct ast_channel *c)
 {
-       struct chan_oss_pvt *o = c->tech_pvt;
+       struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
        ast_verbose(" << Console call has been answered >> \n");
        ast_setstate(c, AST_STATE_UP);
        o->hookstate = 1;
@@ -643,9 +648,9 @@ static int oss_answer(struct ast_channel *c)
 
 static int oss_hangup(struct ast_channel *c)
 {
-       struct chan_oss_pvt *o = c->tech_pvt;
+       struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
 
-       c->tech_pvt = NULL;
+       ast_channel_tech_pvt_set(c, NULL);
        o->owner = NULL;
        ast_verbose(" << Hangup on console >> \n");
        console_video_uninit(o->env);
@@ -664,7 +669,7 @@ static int oss_hangup(struct ast_channel *c)
 static int oss_write(struct ast_channel *c, struct ast_frame *f)
 {
        int src;
-       struct chan_oss_pvt *o = c->tech_pvt;
+       struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
 
        /*
         * we could receive a block which is not a multiple of our
@@ -695,7 +700,7 @@ static int oss_write(struct ast_channel *c, struct ast_frame *f)
 static struct ast_frame *oss_read(struct ast_channel *c)
 {
        int res;
-       struct chan_oss_pvt *o = c->tech_pvt;
+       struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
        struct ast_frame *f = &o->read_f;
 
        /* XXX can be simplified returning &ast_null_frame */
@@ -716,11 +721,11 @@ static struct ast_frame *oss_read(struct ast_channel *c)
                return f;
 
        o->readpos = AST_FRIENDLY_OFFSET;       /* reset read pointer for next frame */
-       if (c->_state != AST_STATE_UP)  /* drop data if frame is not up */
+       if (ast_channel_state(c) != AST_STATE_UP)       /* drop data if frame is not up */
                return f;
        /* ok we can build and deliver the frame to the caller */
        f->frametype = AST_FRAME_VOICE;
-       ast_format_set(&f->subclass.format, AST_FORMAT_SLINEAR, 0);
+       f->subclass.format = ast_format_slin;
        f->samples = FRAME_SIZE;
        f->datalen = FRAME_SIZE * 2;
        f->data.ptr = o->oss_read_buf + AST_FRIENDLY_OFFSET;
@@ -743,14 +748,14 @@ static struct ast_frame *oss_read(struct ast_channel *c)
 
 static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
-       struct chan_oss_pvt *o = newchan->tech_pvt;
+       struct chan_oss_pvt *o = ast_channel_tech_pvt(newchan);
        o->owner = newchan;
        return 0;
 }
 
 static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
 {
-       struct chan_oss_pvt *o = c->tech_pvt;
+       struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
        int res = 0;
 
        switch (cond) {
@@ -758,6 +763,7 @@ static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_
        case AST_CONTROL_BUSY:
        case AST_CONTROL_CONGESTION:
        case AST_CONTROL_RINGING:
+       case AST_CONTROL_PVT_CAUSE_CODE:
        case -1:
                res = -1;
                break;
@@ -775,7 +781,7 @@ static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_
                ast_moh_stop(c);
                break;
        default:
-               ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
+               ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, ast_channel_name(c));
                return -1;
        }
 
@@ -785,46 +791,47 @@ static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_
 /*!
  * \brief allocate a new channel.
  */
-static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state, const char *linkedid)
+static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
 {
        struct ast_channel *c;
 
-       c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, linkedid, 0, "Console/%s", o->device + 5);
+       c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, assignedids, requestor, 0, "Console/%s", o->device + 5);
        if (c == NULL)
                return NULL;
-       c->tech = &oss_tech;
+       ast_channel_tech_set(c, &oss_tech);
        if (o->sounddev < 0)
                setformat(o, O_RDWR);
        ast_channel_set_fd(c, 0, o->sounddev); /* -1 if device closed, override later */
 
-       ast_format_set(&c->readformat, AST_FORMAT_SLINEAR, 0);
-       ast_format_set(&c->writeformat, AST_FORMAT_SLINEAR, 0);
-       ast_format_cap_add(c->nativeformats, &c->readformat);
+       ast_channel_set_readformat(c, ast_format_slin);
+       ast_channel_set_writeformat(c, ast_format_slin);
+       ast_channel_nativeformats_set(c, oss_tech.capabilities);
 
        /* if the console makes the call, add video to the offer */
        /* if (state == AST_STATE_RINGING) TODO XXX CONSOLE VIDEO IS DISABLED UNTIL IT GETS A MAINTAINER
                c->nativeformats |= console_video_formats; */
 
-       c->tech_pvt = o;
+       ast_channel_tech_pvt_set(c, o);
 
        if (!ast_strlen_zero(o->language))
-               ast_string_field_set(c, language, o->language);
+               ast_channel_language_set(c, o->language);
        /* Don't use ast_set_callerid() here because it will
         * generate a needless NewCallerID event */
        if (!ast_strlen_zero(o->cid_num)) {
-               c->caller.ani.number.valid = 1;
-               c->caller.ani.number.str = ast_strdup(o->cid_num);
+               ast_channel_caller(c)->ani.number.valid = 1;
+               ast_channel_caller(c)->ani.number.str = ast_strdup(o->cid_num);
        }
        if (!ast_strlen_zero(ext)) {
-               c->dialed.number.str = ast_strdup(ext);
+               ast_channel_dialed(c)->number.str = ast_strdup(ext);
        }
 
        o->owner = c;
        ast_module_ref(ast_module_info->self);
        ast_jb_configure(c, &global_jbconf);
+       ast_channel_unlock(c);
        if (state != AST_STATE_DOWN) {
                if (ast_pbx_start(c)) {
-                       ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
+                       ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(c));
                        ast_hangup(c);
                        o->owner = c = NULL;
                }
@@ -834,7 +841,7 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx,
        return c;
 }
 
-static struct ast_channel *oss_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int *cause)
+static struct ast_channel *oss_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)
 {
        struct ast_channel *c;
        struct chan_oss_pvt *o;
@@ -843,20 +850,19 @@ static struct ast_channel *oss_request(const char *type, struct ast_format_cap *
                AST_APP_ARG(flags);
        );
        char *parse = ast_strdupa(data);
-       char buf[256];
-       struct ast_format tmpfmt;
 
        AST_NONSTANDARD_APP_ARGS(args, parse, '/');
        o = find_desc(args.name);
 
-       ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, (char *) data);
+       ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, data);
        if (o == NULL) {
                ast_log(LOG_NOTICE, "Device %s not found\n", args.name);
                /* XXX we could default to 'dsp' perhaps ? */
                return NULL;
        }
-       if (!(ast_format_cap_iscompatible(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0)))) {
-               ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
+       if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
+               struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_format_cap_get_names(cap, &codec_buf));
                return NULL;
        }
        if (o->owner) {
@@ -864,7 +870,7 @@ static struct ast_channel *oss_request(const char *type, struct ast_format_cap *
                *cause = AST_CAUSE_BUSY;
                return NULL;
        }
-       c = oss_new(o, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
+       c = oss_new(o, NULL, NULL, AST_STATE_DOWN, assignedids, requestor);
        if (c == NULL) {
                ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
                return NULL;
@@ -1099,16 +1105,16 @@ static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args
        if (o->owner) { /* already in a call */
                int i;
                struct ast_frame f = { AST_FRAME_DTMF, { 0 } };
-               const char *s;
+               const char *digits;
 
                if (a->argc == e->args) {       /* argument is mandatory here */
                        ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
                        return CLI_FAILURE;
                }
-               s = a->argv[e->args];
+               digits = a->argv[e->args];
                /* send the string one char at a time */
-               for (i = 0; i < strlen(s); i++) {
-                       f.subclass.integer = s[i];
+               for (i = 0; i < strlen(digits); i++) {
+                       f.subclass.integer = digits[i];
                        ast_queue_frame(o->owner, &f);
                }
                return CLI_SUCCESS;
@@ -1123,7 +1129,7 @@ static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args
                myc = o->ctx;
        if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
                o->hookstate = 1;
-               oss_new(o, mye, myc, AST_STATE_RINGING, NULL);
+               oss_new(o, mye, myc, AST_STATE_RINGING, NULL, NULL);
        } else
                ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
        if (s)
@@ -1167,7 +1173,6 @@ static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args
 static char *console_transfer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        struct chan_oss_pvt *o = find_desc(oss_active);
-       struct ast_channel *b = NULL;
        char *tmp, *ext, *ctx;
 
        switch (cmd) {
@@ -1186,24 +1191,19 @@ static char *console_transfer(struct ast_cli_entry *e, int cmd, struct ast_cli_a
                return CLI_SHOWUSAGE;
        if (o == NULL)
                return CLI_FAILURE;
-       if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
+       if (o->owner == NULL || !ast_channel_is_bridged(o->owner)) {
                ast_cli(a->fd, "There is no call to transfer\n");
                return CLI_SUCCESS;
        }
 
        tmp = ast_ext_ctx(a->argv[2], &ext, &ctx);
-       if (ctx == NULL)                        /* supply default context if needed */
-               ctx = o->owner->context;
-       if (!ast_exists_extension(b, ctx, ext, 1,
-               S_COR(b->caller.id.number.valid, b->caller.id.number.str, NULL))) {
-               ast_cli(a->fd, "No such extension exists\n");
-       } else {
-               ast_cli(a->fd, "Whee, transferring %s to %s@%s.\n", b->name, ext, ctx);
-               if (ast_async_goto(b, ctx, ext, 1))
-                       ast_cli(a->fd, "Failed to transfer :(\n");
+       if (ctx == NULL) {                      /* supply default context if needed */
+               ctx = ast_strdupa(ast_channel_context(o->owner));
        }
-       if (tmp)
-               ast_free(tmp);
+       if (ast_bridge_transfer_blind(1, o->owner, ext, ctx, NULL, NULL) != AST_BRIDGE_TRANSFER_SUCCESS) {
+               ast_log(LOG_WARNING, "Unable to transfer call from channel %s\n", ast_channel_name(o->owner));
+       }
+       ast_free(tmp);
        return CLI_SUCCESS;
 }
 
@@ -1393,9 +1393,7 @@ static struct chan_oss_pvt *store_config(struct ast_config *cfg, char *ctg)
        if (o->mixer_cmd) {
                char *cmd;
 
-               if (asprintf(&cmd, "mixer %s", o->mixer_cmd) < 0) {
-                       ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
-               } else {
+               if (ast_asprintf(&cmd, "mixer %s", o->mixer_cmd) >= 0) {
                        ast_log(LOG_WARNING, "running [%s]\n", cmd);
                        if (system(cmd) < 0) {
                                ast_log(LOG_WARNING, "system() failed: %s\n", strerror(errno));
@@ -1437,12 +1435,46 @@ error:
 #endif
 }
 
+static int unload_module(void)
+{
+       struct chan_oss_pvt *o, *next;
+
+       ast_channel_unregister(&oss_tech);
+       ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss));
+
+       o = oss_default.next;
+       while (o) {
+               close(o->sounddev);
+               if (o->owner)
+                       ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
+               if (o->owner)
+                       return -1;
+               next = o->next;
+               ast_free(o->name);
+               ast_free(o);
+               o = next;
+       }
+       ao2_cleanup(oss_tech.capabilities);
+       oss_tech.capabilities = NULL;
+
+       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)
 {
        struct ast_config *cfg = NULL;
        char *ctg = NULL;
        struct ast_flags config_flags = { 0 };
-       struct ast_format tmpfmt;
 
        /* Copy the default jb config over global_jbconf */
        memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
@@ -1465,14 +1497,14 @@ static int load_module(void)
        if (find_desc(oss_active) == NULL) {
                ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
                /* XXX we could default to 'dsp' perhaps ? */
-               /* XXX should cleanup allocated memory etc. */
-               return AST_MODULE_LOAD_FAILURE;
+               unload_module();
+               return AST_MODULE_LOAD_DECLINE;
        }
 
-       if (!(oss_tech.capabilities = ast_format_cap_alloc())) {
-               return AST_MODULE_LOAD_FAILURE;
+       if (!(oss_tech.capabilities = ast_format_cap_alloc(0))) {
+               return AST_MODULE_LOAD_DECLINE;
        }
-       ast_format_cap_add(oss_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+       ast_format_cap_append(oss_tech.capabilities, ast_format_slin, 0);
 
        /* TODO XXX CONSOLE VIDEO IS DISABLE UNTIL IT HAS A MAINTAINER
         * add console_video_formats to oss_tech.capabilities once this occurs. */
@@ -1487,28 +1519,5 @@ static int load_module(void)
        return AST_MODULE_LOAD_SUCCESS;
 }
 
+AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "OSS Console Channel Driver");
 
-static int unload_module(void)
-{
-       struct chan_oss_pvt *o, *next;
-
-       ast_channel_unregister(&oss_tech);
-       ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss));
-
-       o = oss_default.next;
-       while (o) {
-               close(o->sounddev);
-               if (o->owner)
-                       ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
-               if (o->owner)
-                       return -1;
-               next = o->next;
-               ast_free(o->name);
-               ast_free(o);
-               o = next;
-       }
-       oss_tech.capabilities = ast_format_cap_destroy(oss_tech.capabilities);
-       return 0;
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "OSS Console Channel Driver");