Fri Aug 17 00:17:30 2018

Asterisk developer's documentation


chan_oss.c File Reference

Channel driver for OSS sound cards. More...

#include "asterisk.h"
#include <ctype.h>
#include <math.h>
#include <sys/ioctl.h>
#include <soundcard.h>
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/cli.h"
#include "asterisk/causes.h"
#include "asterisk/musiconhold.h"
#include "asterisk/app.h"
#include "console_video.h"

Go to the source code of this file.

Data Structures

struct  chan_oss_pvt
 descriptor for one of our channels. More...

Defines

#define BOOST_MAX   40
#define BOOST_SCALE   (1<<9)
#define DEV_DSP   "/dev/dsp"
#define FRAGS   ( ( (6 * 5) << 16 ) | 0x6 )
#define FRAME_SIZE   160
#define O_CLOSE   0x444
#define QUEUE_SIZE   10
#define TEXT_SIZE   256
#define WARN_frag   4
#define WARN_speed   2
#define WARN_used_blocks   1

Functions

static char * ast_ext_ctx (const char *src, char **ext, char **ctx)
 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"OSS Console Channel Driver")
static char * console_active (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_answer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 answer command from the console
static char * console_autoanswer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_boost (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_dial (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_do_answer (int fd)
 helper function for the answer key/cli command
static char * console_flash (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_hangup (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_mute (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * console_sendtext (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Console send text CLI command.
static char * console_transfer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct chan_oss_pvtfind_desc (const char *dev)
 returns a pointer to the descriptor with the given name
struct video_desc * get_video_desc (struct ast_channel *c)
 return the pointer to the video descriptor
static int load_module (void)
static int oss_answer (struct ast_channel *c)
 remote side answered the phone
static int oss_call (struct ast_channel *c, char *dest, int timeout)
 handler for incoming calls. Either autoanswer, or start ringing
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_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static int oss_hangup (struct ast_channel *c)
static int oss_indicate (struct ast_channel *chan, int cond, const void *data, size_t datalen)
static struct ast_channeloss_new (struct chan_oss_pvt *o, char *ext, char *ctx, int state, const char *linkedid)
 allocate a new channel.
static struct ast_frameoss_read (struct ast_channel *chan)
static struct ast_channeloss_request (const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
static int oss_text (struct ast_channel *c, const char *text)
static int oss_write (struct ast_channel *c, struct ast_frame *f)
 used for data coming from the network
static int setformat (struct chan_oss_pvt *o, int mode)
static int soundcard_writeframe (struct chan_oss_pvt *o, short *data)
static void store_boost (struct chan_oss_pvt *o, const char *s)
 store the boost factor
static void store_callerid (struct chan_oss_pvt *o, const char *s)
static struct chan_oss_pvtstore_config (struct ast_config *cfg, char *ctg)
static void store_config_core (struct chan_oss_pvt *o, const char *var, const char *value)
static void store_mixer (struct chan_oss_pvt *o, const char *s)
static int unload_module (void)
static int used_blocks (struct chan_oss_pvt *o)
 Returns the number of blocks used in the audio output channel.

Variables

static struct ast_cli_entry cli_oss []
static char * config = "oss.conf"
static struct ast_jb_conf default_jbconf
static struct ast_jb_conf global_jbconf
static char * oss_active
static int oss_debug
static struct chan_oss_pvt oss_default
static struct ast_channel_tech oss_tech
static char tdesc [] = "OSS Console Channel Driver"

Detailed Description

Channel driver for OSS sound cards.

Author:
Mark Spencer <markster@digium.com>
Luigi Rizzo
See also

Definition in file chan_oss.c.


Define Documentation

#define BOOST_MAX   40

slightly less than 7 bits

Definition at line 275 of file chan_oss.c.

Referenced by store_boost().

#define BOOST_SCALE   (1<<9)

boost support. BOOST_SCALE * 10 ^(BOOST_MAX/20) must be representable in 16 bits to avoid overflows.

Definition at line 274 of file chan_oss.c.

Referenced by console_boost(), oss_read(), and store_boost().

#define DEV_DSP   "/dev/dsp"

Definition at line 232 of file chan_oss.c.

Referenced by store_config().

#define FRAGS   ( ( (6 * 5) << 16 ) | 0x6 )

Definition at line 215 of file chan_oss.c.

#define FRAME_SIZE   160

Definition at line 209 of file chan_oss.c.

#define O_CLOSE   0x444

Definition at line 227 of file chan_oss.c.

Referenced by console_hangup(), oss_hangup(), and setformat().

#define QUEUE_SIZE   10

Definition at line 210 of file chan_oss.c.

#define TEXT_SIZE   256

Definition at line 222 of file chan_oss.c.

#define WARN_frag   4

Definition at line 264 of file chan_oss.c.

Referenced by setformat().

#define WARN_speed   2

Definition at line 263 of file chan_oss.c.

Referenced by setformat().

#define WARN_used_blocks   1

Definition at line 262 of file chan_oss.c.

Referenced by used_blocks().


Function Documentation

static char* ast_ext_ctx ( const char *  src,
char **  ext,
char **  ctx 
) [static]

Definition at line 393 of file chan_oss.c.

References ast_strdup, find_desc(), and chan_oss_pvt::overridecontext.

Referenced by console_dial(), and console_transfer().

00394 {
00395    struct chan_oss_pvt *o = find_desc(oss_active);
00396 
00397    if (ext == NULL || ctx == NULL)
00398       return NULL;         /* error */
00399 
00400    *ext = *ctx = NULL;
00401 
00402    if (src && *src != '\0')
00403       *ext = ast_strdup(src);
00404 
00405    if (*ext == NULL)
00406       return NULL;
00407 
00408    if (!o->overridecontext) {
00409       /* parse from the right */
00410       *ctx = strrchr(*ext, '@');
00411       if (*ctx)
00412          *(*ctx)++ = '\0';
00413    }
00414 
00415    return *ext;
00416 }

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"OSS Console Channel Driver"   
)
static char* console_active ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1208 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, find_desc(), chan_oss_pvt::name, chan_oss_pvt::next, and ast_cli_entry::usage.

01209 {
01210    switch (cmd) {
01211    case CLI_INIT:
01212       e->command = "console {set|show} active [<device>]";
01213       e->usage =
01214          "Usage: console active [device]\n"
01215          "       If used without a parameter, displays which device is the current\n"
01216          "       console.  If a device is specified, the console sound device is changed to\n"
01217          "       the device specified.\n";
01218       return NULL;
01219    case CLI_GENERATE:
01220       return NULL;
01221    }
01222 
01223    if (a->argc == 3)
01224       ast_cli(a->fd, "active console is [%s]\n", oss_active);
01225    else if (a->argc != 4)
01226       return CLI_SHOWUSAGE;
01227    else {
01228       struct chan_oss_pvt *o;
01229       if (strcmp(a->argv[3], "show") == 0) {
01230          for (o = oss_default.next; o; o = o->next)
01231             ast_cli(a->fd, "device [%s] exists\n", o->name);
01232          return CLI_SUCCESS;
01233       }
01234       o = find_desc(a->argv[3]);
01235       if (o == NULL)
01236          ast_cli(a->fd, "No device [%s] exists\n", a->argv[3]);
01237       else
01238          oss_active = o->name;
01239    }
01240    return CLI_SUCCESS;
01241 }

static char* console_answer ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

answer command from the console

Definition at line 970 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, console_do_answer(), ast_cli_args::fd, and ast_cli_entry::usage.

00971 {
00972    switch (cmd) {
00973    case CLI_INIT:
00974       e->command = "console answer";
00975       e->usage =
00976          "Usage: console answer\n"
00977          "       Answers an incoming call on the console (OSS) channel.\n";
00978       return NULL;
00979 
00980    case CLI_GENERATE:
00981       return NULL;   /* no completion */
00982    }
00983    if (a->argc != e->args)
00984       return CLI_SHOWUSAGE;
00985    return console_do_answer(a->fd);
00986 }

static char* console_autoanswer ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 914 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ast_log(), chan_oss_pvt::autoanswer, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, find_desc(), LOG_WARNING, and ast_cli_entry::usage.

00915 {
00916    struct chan_oss_pvt *o = find_desc(oss_active);
00917 
00918    switch (cmd) {
00919    case CLI_INIT:
00920       e->command = "console {set|show} autoanswer [on|off]";
00921       e->usage =
00922          "Usage: console {set|show} autoanswer [on|off]\n"
00923          "       Enables or disables autoanswer feature.  If used without\n"
00924          "       argument, displays the current on/off status of autoanswer.\n"
00925          "       The default value of autoanswer is in 'oss.conf'.\n";
00926       return NULL;
00927 
00928    case CLI_GENERATE:
00929       return NULL;
00930    }
00931 
00932    if (a->argc == e->args - 1) {
00933       ast_cli(a->fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
00934       return CLI_SUCCESS;
00935    }
00936    if (a->argc != e->args)
00937       return CLI_SHOWUSAGE;
00938    if (o == NULL) {
00939       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00940           oss_active);
00941       return CLI_FAILURE;
00942    }
00943    if (!strcasecmp(a->argv[e->args-1], "on"))
00944       o->autoanswer = 1;
00945    else if (!strcasecmp(a->argv[e->args - 1], "off"))
00946       o->autoanswer = 0;
00947    else
00948       return CLI_SHOWUSAGE;
00949    return CLI_SUCCESS;
00950 }

static char* console_boost ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1265 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), chan_oss_pvt::boost, BOOST_SCALE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, find_desc(), store_boost(), and ast_cli_entry::usage.

01266 {
01267    struct chan_oss_pvt *o = find_desc(oss_active);
01268 
01269    switch (cmd) {
01270    case CLI_INIT:
01271       e->command = "console boost";
01272       e->usage =
01273          "Usage: console boost [boost in dB]\n"
01274          "       Sets or display mic boost in dB\n";
01275       return NULL;
01276    case CLI_GENERATE:
01277       return NULL;
01278    }
01279 
01280    if (a->argc == 2)
01281       ast_cli(a->fd, "boost currently %5.1f\n", 20 * log10(((double) o->boost / (double) BOOST_SCALE)));
01282    else if (a->argc == 3)
01283       store_boost(o, a->argv[2]);
01284    return CLI_SUCCESS;
01285 }

static char* console_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Generic console command handler. Basically a wrapper for a subset of config file options which are also available from the CLI

Definition at line 878 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ast_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, console_video_cli(), CONSOLE_VIDEO_CMDS, chan_oss_pvt::device, chan_oss_pvt::env, ast_cli_args::fd, find_desc(), LOG_WARNING, store_config_core(), ast_cli_entry::usage, value, and var.

00879 {
00880    struct chan_oss_pvt *o = find_desc(oss_active);
00881    const char *var, *value;
00882    switch (cmd) {
00883    case CLI_INIT:
00884       e->command = CONSOLE_VIDEO_CMDS;
00885       e->usage = 
00886          "Usage: " CONSOLE_VIDEO_CMDS "...\n"
00887          "       Generic handler for console commands.\n";
00888       return NULL;
00889 
00890    case CLI_GENERATE:
00891       return NULL;
00892    }
00893 
00894    if (a->argc < e->args)
00895       return CLI_SHOWUSAGE;
00896    if (o == NULL) {
00897       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
00898          oss_active);
00899       return CLI_FAILURE;
00900    }
00901    var = a->argv[e->args-1];
00902    value = a->argc > e->args ? a->argv[e->args] : NULL;
00903    if (value)      /* handle setting */
00904       store_config_core(o, var, value);
00905    if (!console_video_cli(o->env, var, a->fd))  /* print video-related values */
00906       return CLI_SUCCESS;
00907    /* handle other values */
00908    if (!strcasecmp(var, "device")) {
00909       ast_cli(a->fd, "device is [%s]\n", o->device);
00910    }
00911    return CLI_SUCCESS;
00912 }

static char* console_dial ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1080 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ast_exists_extension(), ast_ext_ctx(), AST_FRAME_DTMF, ast_free, ast_queue_frame(), AST_STATE_RINGING, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, chan_oss_pvt::ctx, chan_oss_pvt::ext, ast_cli_args::fd, find_desc(), chan_oss_pvt::hookstate, ast_frame_subclass::integer, oss_new(), chan_oss_pvt::owner, ast_frame::subclass, and ast_cli_entry::usage.

01081 {
01082    char *s = NULL;
01083    char *mye = NULL, *myc = NULL;
01084    struct chan_oss_pvt *o = find_desc(oss_active);
01085 
01086    if (cmd == CLI_INIT) {
01087       e->command = "console dial";
01088       e->usage =
01089          "Usage: console dial [extension[@context]]\n"
01090          "       Dials a given extension (and context if specified)\n";
01091       return NULL;
01092    } else if (cmd == CLI_GENERATE)
01093       return NULL;
01094 
01095    if (a->argc > e->args + 1)
01096       return CLI_SHOWUSAGE;
01097    if (o->owner) {   /* already in a call */
01098       int i;
01099       struct ast_frame f = { AST_FRAME_DTMF, { 0 } };
01100       const char *s;
01101 
01102       if (a->argc == e->args) {  /* argument is mandatory here */
01103          ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
01104          return CLI_FAILURE;
01105       }
01106       s = a->argv[e->args];
01107       /* send the string one char at a time */
01108       for (i = 0; i < strlen(s); i++) {
01109          f.subclass.integer = s[i];
01110          ast_queue_frame(o->owner, &f);
01111       }
01112       return CLI_SUCCESS;
01113    }
01114    /* if we have an argument split it into extension and context */
01115    if (a->argc == e->args + 1)
01116       s = ast_ext_ctx(a->argv[e->args], &mye, &myc);
01117    /* supply default values if needed */
01118    if (mye == NULL)
01119       mye = o->ext;
01120    if (myc == NULL)
01121       myc = o->ctx;
01122    if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01123       o->hookstate = 1;
01124       oss_new(o, mye, myc, AST_STATE_RINGING, NULL);
01125    } else
01126       ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
01127    if (s)
01128       ast_free(s);
01129    return CLI_SUCCESS;
01130 }

static char* console_do_answer ( int  fd  )  [static]

helper function for the answer key/cli command

Definition at line 953 of file chan_oss.c.

References ast_cli(), AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_queue_frame(), CLI_FAILURE, CLI_SUCCESS, find_desc(), chan_oss_pvt::hookstate, and chan_oss_pvt::owner.

Referenced by console_answer().

00954 {
00955    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00956    struct chan_oss_pvt *o = find_desc(oss_active);
00957    if (!o->owner) {
00958       if (fd > -1)
00959          ast_cli(fd, "No one is calling us\n");
00960       return CLI_FAILURE;
00961    }
00962    o->hookstate = 1;
00963    ast_queue_frame(o->owner, &f);
00964    return CLI_SUCCESS;
00965 }

static char* console_flash ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1054 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli(), AST_CONTROL_FLASH, AST_FRAME_CONTROL, ast_queue_frame(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, find_desc(), chan_oss_pvt::hookstate, chan_oss_pvt::owner, and ast_cli_entry::usage.

01055 {
01056    struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH } };
01057    struct chan_oss_pvt *o = find_desc(oss_active);
01058 
01059    if (cmd == CLI_INIT) {
01060       e->command = "console flash";
01061       e->usage =
01062          "Usage: console flash\n"
01063          "       Flashes the call currently placed on the console.\n";
01064       return NULL;
01065    } else if (cmd == CLI_GENERATE)
01066       return NULL;
01067 
01068    if (a->argc != e->args)
01069       return CLI_SHOWUSAGE;
01070    if (!o->owner) {        /* XXX maybe !o->hookstate too ? */
01071       ast_cli(a->fd, "No call to flash\n");
01072       return CLI_FAILURE;
01073    }
01074    o->hookstate = 0;
01075    if (o->owner)
01076       ast_queue_frame(o->owner, &f);
01077    return CLI_SUCCESS;
01078 }

static char* console_hangup ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1028 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, AST_CAUSE_NORMAL_CLEARING, ast_cli(), ast_queue_hangup_with_cause(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, find_desc(), chan_oss_pvt::hookstate, O_CLOSE, chan_oss_pvt::owner, setformat(), and ast_cli_entry::usage.

01029 {
01030    struct chan_oss_pvt *o = find_desc(oss_active);
01031 
01032    if (cmd == CLI_INIT) {
01033       e->command = "console hangup";
01034       e->usage =
01035          "Usage: console hangup\n"
01036          "       Hangs up any call currently placed on the console.\n";
01037       return NULL;
01038    } else if (cmd == CLI_GENERATE)
01039       return NULL;
01040 
01041    if (a->argc != e->args)
01042       return CLI_SHOWUSAGE;
01043    if (!o->owner && !o->hookstate) { /* XXX maybe only one ? */
01044       ast_cli(a->fd, "No call to hang up\n");
01045       return CLI_FAILURE;
01046    }
01047    o->hookstate = 0;
01048    if (o->owner)
01049       ast_queue_hangup_with_cause(o->owner, AST_CAUSE_NORMAL_CLEARING);
01050    setformat(o, O_CLOSE);
01051    return CLI_SUCCESS;
01052 }

static char* console_mute ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1132 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, find_desc(), chan_oss_pvt::mute, and ast_cli_entry::usage.

01133 {
01134    struct chan_oss_pvt *o = find_desc(oss_active);
01135    const char *s;
01136    int toggle = 0;
01137    
01138    if (cmd == CLI_INIT) {
01139       e->command = "console {mute|unmute} [toggle]";
01140       e->usage =
01141          "Usage: console {mute|unmute} [toggle]\n"
01142          "       Mute/unmute the microphone.\n";
01143       return NULL;
01144    } else if (cmd == CLI_GENERATE)
01145       return NULL;
01146 
01147    if (a->argc > e->args)
01148       return CLI_SHOWUSAGE;
01149    if (a->argc == e->args) {
01150       if (strcasecmp(a->argv[e->args-1], "toggle"))
01151          return CLI_SHOWUSAGE;
01152       toggle = 1;
01153    }
01154    s = a->argv[e->args-2];
01155    if (!strcasecmp(s, "mute"))
01156       o->mute = toggle ? !o->mute : 1;
01157    else if (!strcasecmp(s, "unmute"))
01158       o->mute = toggle ? !o->mute : 0;
01159    else
01160       return CLI_SHOWUSAGE;
01161    ast_cli(a->fd, "Console mic is %s\n", o->mute ? "off" : "on");
01162    return CLI_SUCCESS;
01163 }

static char* console_sendtext ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Console send text CLI command.

Note:
concatenate all arguments into a single string. argv is NULL-terminated so we can use it right away

Definition at line 994 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), AST_FRAME_TEXT, ast_join(), ast_queue_frame(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_frame::data, ast_frame::datalen, ast_cli_args::fd, find_desc(), ast_frame::frametype, ast_frame_subclass::integer, chan_oss_pvt::owner, ast_frame::ptr, ast_frame::subclass, TEXT_SIZE, and ast_cli_entry::usage.

00995 {
00996    struct chan_oss_pvt *o = find_desc(oss_active);
00997    char buf[TEXT_SIZE];
00998 
00999    if (cmd == CLI_INIT) {
01000       e->command = "console send text";
01001       e->usage =
01002          "Usage: console send text <message>\n"
01003          "       Sends a text message for display on the remote terminal.\n";
01004       return NULL;
01005    } else if (cmd == CLI_GENERATE)
01006       return NULL;
01007 
01008    if (a->argc < e->args + 1)
01009       return CLI_SHOWUSAGE;
01010    if (!o->owner) {
01011       ast_cli(a->fd, "Not in a call\n");
01012       return CLI_FAILURE;
01013    }
01014    ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01015    if (!ast_strlen_zero(buf)) {
01016       struct ast_frame f = { 0, };
01017       int i = strlen(buf);
01018       buf[i] = '\n';
01019       f.frametype = AST_FRAME_TEXT;
01020       f.subclass.integer = 0;
01021       f.data.ptr = buf;
01022       f.datalen = i + 1;
01023       ast_queue_frame(o->owner, &f);
01024    }
01025    return CLI_SUCCESS;
01026 }

static char* console_transfer ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1165 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_async_goto(), ast_bridged_channel(), ast_cli(), ast_exists_extension(), ast_ext_ctx(), ast_free, ast_channel::caller, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_channel::context, ext, ast_cli_args::fd, find_desc(), ast_party_caller::id, ast_party_id::number, chan_oss_pvt::owner, S_COR, ast_party_number::str, ast_cli_entry::usage, and ast_party_number::valid.

01166 {
01167    struct chan_oss_pvt *o = find_desc(oss_active);
01168    struct ast_channel *b = NULL;
01169    char *tmp, *ext, *ctx;
01170 
01171    switch (cmd) {
01172    case CLI_INIT:
01173       e->command = "console transfer";
01174       e->usage =
01175          "Usage: console transfer <extension>[@context]\n"
01176          "       Transfers the currently connected call to the given extension (and\n"
01177          "       context if specified)\n";
01178       return NULL;
01179    case CLI_GENERATE:
01180       return NULL;
01181    }
01182 
01183    if (a->argc != 3)
01184       return CLI_SHOWUSAGE;
01185    if (o == NULL)
01186       return CLI_FAILURE;
01187    if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
01188       ast_cli(a->fd, "There is no call to transfer\n");
01189       return CLI_SUCCESS;
01190    }
01191 
01192    tmp = ast_ext_ctx(a->argv[2], &ext, &ctx);
01193    if (ctx == NULL)        /* supply default context if needed */
01194       ctx = o->owner->context;
01195    if (!ast_exists_extension(b, ctx, ext, 1,
01196       S_COR(b->caller.id.number.valid, b->caller.id.number.str, NULL))) {
01197       ast_cli(a->fd, "No such extension exists\n");
01198    } else {
01199       ast_cli(a->fd, "Whee, transferring %s to %s@%s.\n", b->name, ext, ctx);
01200       if (ast_async_goto(b, ctx, ext, 1))
01201          ast_cli(a->fd, "Failed to transfer :(\n");
01202    }
01203    if (tmp)
01204       ast_free(tmp);
01205    return CLI_SUCCESS;
01206 }

static struct chan_oss_pvt * find_desc ( const char *  dev  )  [static, read]

returns a pointer to the descriptor with the given name

forward declaration

Definition at line 367 of file chan_oss.c.

References ast_log(), LOG_WARNING, chan_oss_pvt::name, and chan_oss_pvt::next.

Referenced by ast_ext_ctx(), console_active(), console_autoanswer(), console_boost(), console_cmd(), console_dial(), console_do_answer(), console_flash(), console_hangup(), console_mute(), console_sendtext(), console_transfer(), get_video_desc(), load_module(), and oss_request().

00368 {
00369    struct chan_oss_pvt *o = NULL;
00370 
00371    if (!dev)
00372       ast_log(LOG_WARNING, "null dev\n");
00373 
00374    for (o = oss_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next);
00375 
00376    if (!o)
00377       ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
00378 
00379    return o;
00380 }

struct video_desc* get_video_desc ( struct ast_channel c  )  [read]

return the pointer to the video descriptor

Definition at line 309 of file chan_oss.c.

References chan_oss_pvt::env, find_desc(), and ast_channel::tech_pvt.

Referenced by oss_new().

00310 {
00311    struct chan_oss_pvt *o = c ? c->tech_pvt : find_desc(oss_active);
00312    return o ? o->env : NULL;
00313 }

static int load_module ( void   )  [static]

Definition at line 1436 of file chan_oss.c.

References ARRAY_LEN, ast_category_browse(), ast_channel_register(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_channel_tech::capabilities, CONFIG_STATUS_FILEINVALID, console_video_formats, find_desc(), global_jbconf, LOG_ERROR, LOG_NOTICE, and store_config().

01437 {
01438    struct ast_config *cfg = NULL;
01439    char *ctg = NULL;
01440    struct ast_flags config_flags = { 0 };
01441 
01442    /* Copy the default jb config over global_jbconf */
01443    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01444 
01445    /* load config file */
01446    if (!(cfg = ast_config_load(config, config_flags))) {
01447       ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
01448       return AST_MODULE_LOAD_DECLINE;
01449    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01450       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
01451       return AST_MODULE_LOAD_DECLINE;
01452    }
01453 
01454    do {
01455       store_config(cfg, ctg);
01456    } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
01457 
01458    ast_config_destroy(cfg);
01459 
01460    if (find_desc(oss_active) == NULL) {
01461       ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
01462       /* XXX we could default to 'dsp' perhaps ? */
01463       /* XXX should cleanup allocated memory etc. */
01464       return AST_MODULE_LOAD_FAILURE;
01465    }
01466 
01467    oss_tech.capabilities |= console_video_formats;
01468 
01469    if (ast_channel_register(&oss_tech)) {
01470       ast_log(LOG_ERROR, "Unable to register channel type 'OSS'\n");
01471       return AST_MODULE_LOAD_DECLINE;
01472    }
01473 
01474    ast_cli_register_multiple(cli_oss, ARRAY_LEN(cli_oss));
01475 
01476    return AST_MODULE_LOAD_SUCCESS;
01477 }

static int oss_answer ( struct ast_channel c  )  [static]

remote side answered the phone

Definition at line 636 of file chan_oss.c.

References ast_setstate(), AST_STATE_UP, ast_verbose, chan_oss_pvt::hookstate, and ast_channel::tech_pvt.

00637 {
00638    struct chan_oss_pvt *o = c->tech_pvt;
00639    ast_verbose(" << Console call has been answered >> \n");
00640    ast_setstate(c, AST_STATE_UP);
00641    o->hookstate = 1;
00642    return 0;
00643 }

static int oss_call ( struct ast_channel c,
char *  dest,
int  timeout 
) [static]

handler for incoming calls. Either autoanswer, or start ringing

Definition at line 594 of file chan_oss.c.

References args, AST_APP_ARG, AST_CONTROL_ANSWER, AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, AST_FRAME_CONTROL, ast_indicate(), AST_NONSTANDARD_APP_ARGS, ast_queue_frame(), ast_strdupa, ast_strlen_zero(), ast_verbose, chan_oss_pvt::autoanswer, ast_channel::caller, ast_channel::dialed, ast_frame::flags, ast_party_redirecting::from, chan_oss_pvt::hookstate, ast_party_caller::id, ast_frame_subclass::integer, ast_party_id::name, name, ast_party_id::number, ast_party_dialed::number, parse(), ast_channel::redirecting, S_COR, S_OR, ast_party_name::str, ast_party_number::str, ast_party_dialed::str, ast_frame::subclass, ast_channel::tech_pvt, ast_party_name::valid, and ast_party_number::valid.

00595 {
00596    struct chan_oss_pvt *o = c->tech_pvt;
00597    struct ast_frame f = { AST_FRAME_CONTROL, };
00598    AST_DECLARE_APP_ARGS(args,
00599       AST_APP_ARG(name);
00600       AST_APP_ARG(flags);
00601    );
00602    char *parse = ast_strdupa(dest);
00603 
00604    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
00605 
00606    ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n",
00607       dest,
00608       S_OR(c->dialed.number.str, ""),
00609       S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, ""),
00610       S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
00611       S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""));
00612    if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "answer") == 0) {
00613       f.subclass.integer = AST_CONTROL_ANSWER;
00614       ast_queue_frame(c, &f);
00615    } else if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "noanswer") == 0) {
00616       f.subclass.integer = AST_CONTROL_RINGING;
00617       ast_queue_frame(c, &f);
00618       ast_indicate(c, AST_CONTROL_RINGING);
00619    } else if (o->autoanswer) {
00620       ast_verbose(" << Auto-answered >> \n");
00621       f.subclass.integer = AST_CONTROL_ANSWER;
00622       ast_queue_frame(c, &f);
00623       o->hookstate = 1;
00624    } else {
00625       ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00626       f.subclass.integer = AST_CONTROL_RINGING;
00627       ast_queue_frame(c, &f);
00628       ast_indicate(c, AST_CONTROL_RINGING);
00629    }
00630    return 0;
00631 }

static int oss_digit_begin ( struct ast_channel c,
char  digit 
) [static]

Definition at line 571 of file chan_oss.c.

00572 {
00573    return 0;
00574 }

static int oss_digit_end ( struct ast_channel c,
char  digit,
unsigned int  duration 
) [static]

Definition at line 576 of file chan_oss.c.

References ast_verbose.

00577 {
00578    /* no better use for received digits than print them */
00579    ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
00580       digit, duration);
00581    return 0;
00582 }

static int oss_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 745 of file chan_oss.c.

References chan_oss_pvt::owner, and ast_channel::tech_pvt.

00746 {
00747    struct chan_oss_pvt *o = newchan->tech_pvt;
00748    o->owner = newchan;
00749    return 0;
00750 }

static int oss_hangup ( struct ast_channel c  )  [static]

Definition at line 645 of file chan_oss.c.

References ast_module_unref(), ast_verbose, chan_oss_pvt::autoanswer, chan_oss_pvt::autohangup, console_video_uninit(), chan_oss_pvt::env, chan_oss_pvt::hookstate, O_CLOSE, chan_oss_pvt::owner, setformat(), and ast_channel::tech_pvt.

00646 {
00647    struct chan_oss_pvt *o = c->tech_pvt;
00648 
00649    c->tech_pvt = NULL;
00650    o->owner = NULL;
00651    ast_verbose(" << Hangup on console >> \n");
00652    console_video_uninit(o->env);
00653    ast_module_unref(ast_module_info->self);
00654    if (o->hookstate) {
00655       if (o->autoanswer || o->autohangup) {
00656          /* Assume auto-hangup too */
00657          o->hookstate = 0;
00658          setformat(o, O_CLOSE);
00659       }
00660    }
00661    return 0;
00662 }

static int oss_indicate ( struct ast_channel chan,
int  cond,
const void *  data,
size_t  datalen 
) [static]

Definition at line 752 of file chan_oss.c.

References AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_INCOMPLETE, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_log(), ast_moh_start(), ast_moh_stop(), ast_verbose, LOG_WARNING, chan_oss_pvt::mohinterpret, and ast_channel::tech_pvt.

00753 {
00754    struct chan_oss_pvt *o = c->tech_pvt;
00755    int res = 0;
00756 
00757    switch (cond) {
00758    case AST_CONTROL_INCOMPLETE:
00759    case AST_CONTROL_BUSY:
00760    case AST_CONTROL_CONGESTION:
00761    case AST_CONTROL_RINGING:
00762    case -1:
00763       res = -1;
00764       break;
00765    case AST_CONTROL_PROGRESS:
00766    case AST_CONTROL_PROCEEDING:
00767    case AST_CONTROL_VIDUPDATE:
00768    case AST_CONTROL_SRCUPDATE:
00769       break;
00770    case AST_CONTROL_HOLD:
00771       ast_verbose(" << Console Has Been Placed on Hold >> \n");
00772       ast_moh_start(c, data, o->mohinterpret);
00773       break;
00774    case AST_CONTROL_UNHOLD:
00775       ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00776       ast_moh_stop(c);
00777       break;
00778    default:
00779       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
00780       return -1;
00781    }
00782 
00783    return res;
00784 }

static struct ast_channel* oss_new ( struct chan_oss_pvt o,
char *  ext,
char *  ctx,
int  state,
const char *  linkedid 
) [static, read]

allocate a new channel.

Definition at line 789 of file chan_oss.c.

References ast_party_caller::ani, ast_channel_alloc, ast_channel_set_fd(), AST_FORMAT_SLINEAR, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), AST_STATE_DOWN, AST_STATE_RINGING, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_channel::caller, chan_oss_pvt::cid_name, chan_oss_pvt::cid_num, console_video_formats, console_video_start(), chan_oss_pvt::device, ast_channel::dialed, get_video_desc(), global_jbconf, language, chan_oss_pvt::language, LOG_WARNING, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, chan_oss_pvt::owner, ast_channel::readformat, setformat(), chan_oss_pvt::sounddev, ast_party_dialed::str, ast_party_number::str, ast_channel::tech, ast_channel::tech_pvt, ast_party_number::valid, and ast_channel::writeformat.

Referenced by console_dial(), and oss_request().

00790 {
00791    struct ast_channel *c;
00792 
00793    c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, linkedid, 0, "Console/%s", o->device + 5);
00794    if (c == NULL)
00795       return NULL;
00796    c->tech = &oss_tech;
00797    if (o->sounddev < 0)
00798       setformat(o, O_RDWR);
00799    ast_channel_set_fd(c, 0, o->sounddev); /* -1 if device closed, override later */
00800    c->nativeformats = AST_FORMAT_SLINEAR;
00801    /* if the console makes the call, add video to the offer */
00802    if (state == AST_STATE_RINGING)
00803       c->nativeformats |= console_video_formats;
00804 
00805    c->readformat = AST_FORMAT_SLINEAR;
00806    c->writeformat = AST_FORMAT_SLINEAR;
00807    c->tech_pvt = o;
00808 
00809    if (!ast_strlen_zero(o->language))
00810       ast_string_field_set(c, language, o->language);
00811    /* Don't use ast_set_callerid() here because it will
00812     * generate a needless NewCallerID event */
00813    if (!ast_strlen_zero(o->cid_num)) {
00814       c->caller.ani.number.valid = 1;
00815       c->caller.ani.number.str = ast_strdup(o->cid_num);
00816    }
00817    if (!ast_strlen_zero(ext)) {
00818       c->dialed.number.str = ast_strdup(ext);
00819    }
00820 
00821    o->owner = c;
00822    ast_module_ref(ast_module_info->self);
00823    ast_jb_configure(c, &global_jbconf);
00824    if (state != AST_STATE_DOWN) {
00825       if (ast_pbx_start(c)) {
00826          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
00827          ast_hangup(c);
00828          o->owner = c = NULL;
00829       }
00830    }
00831    console_video_start(get_video_desc(c), c); /* XXX cleanup */
00832 
00833    return c;
00834 }

static struct ast_frame * oss_read ( struct ast_channel chan  )  [static, read]

Definition at line 696 of file chan_oss.c.

References ast_channel::_state, AST_FORMAT_SLINEAR, AST_FRAME_NULL, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, AST_STATE_UP, chan_oss_pvt::boost, BOOST_SCALE, ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, f, FRAME_SIZE, ast_frame::frametype, chan_oss_pvt::mute, ast_frame::offset, chan_oss_pvt::oss_read_buf, ast_frame::ptr, chan_oss_pvt::read_f, chan_oss_pvt::readpos, ast_frame::samples, chan_oss_pvt::sounddev, ast_frame::src, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel_tech::type.

00697 {
00698    int res;
00699    struct chan_oss_pvt *o = c->tech_pvt;
00700    struct ast_frame *f = &o->read_f;
00701 
00702    /* XXX can be simplified returning &ast_null_frame */
00703    /* prepare a NULL frame in case we don't have enough data to return */
00704    memset(f, '\0', sizeof(struct ast_frame));
00705    f->frametype = AST_FRAME_NULL;
00706    f->src = oss_tech.type;
00707 
00708    res = read(o->sounddev, o->oss_read_buf + o->readpos, sizeof(o->oss_read_buf) - o->readpos);
00709    if (res < 0)            /* audio data not ready, return a NULL frame */
00710       return f;
00711 
00712    o->readpos += res;
00713    if (o->readpos < sizeof(o->oss_read_buf)) /* not enough samples */
00714       return f;
00715 
00716    if (o->mute)
00717       return f;
00718 
00719    o->readpos = AST_FRIENDLY_OFFSET;   /* reset read pointer for next frame */
00720    if (c->_state != AST_STATE_UP)   /* drop data if frame is not up */
00721       return f;
00722    /* ok we can build and deliver the frame to the caller */
00723    f->frametype = AST_FRAME_VOICE;
00724    f->subclass.codec = AST_FORMAT_SLINEAR;
00725    f->samples = FRAME_SIZE;
00726    f->datalen = FRAME_SIZE * 2;
00727    f->data.ptr = o->oss_read_buf + AST_FRIENDLY_OFFSET;
00728    if (o->boost != BOOST_SCALE) {   /* scale and clip values */
00729       int i, x;
00730       int16_t *p = (int16_t *) f->data.ptr;
00731       for (i = 0; i < f->samples; i++) {
00732          x = (p[i] * o->boost) / BOOST_SCALE;
00733          if (x > 32767)
00734             x = 32767;
00735          else if (x < -32768)
00736             x = -32768;
00737          p[i] = x;
00738       }
00739    }
00740 
00741    f->offset = AST_FRIENDLY_OFFSET;
00742    return f;
00743 }

static struct ast_channel * oss_request ( const char *  type,
format_t  format,
const struct ast_channel requestor,
void *  data,
int *  cause 
) [static, read]

Definition at line 836 of file chan_oss.c.

References args, AST_APP_ARG, AST_CAUSE_BUSY, AST_DECLARE_APP_ARGS, AST_FORMAT_SLINEAR, ast_getformatname_multiple(), ast_log(), AST_NONSTANDARD_APP_ARGS, AST_STATE_DOWN, ast_strdupa, find_desc(), LOG_NOTICE, LOG_WARNING, name, oss_new(), chan_oss_pvt::owner, and parse().

00837 {
00838    struct ast_channel *c;
00839    struct chan_oss_pvt *o;
00840    AST_DECLARE_APP_ARGS(args,
00841       AST_APP_ARG(name);
00842       AST_APP_ARG(flags);
00843    );
00844    char *parse = ast_strdupa(data);
00845    char buf[256];
00846 
00847    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
00848    o = find_desc(args.name);
00849 
00850    ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, (char *) data);
00851    if (o == NULL) {
00852       ast_log(LOG_NOTICE, "Device %s not found\n", args.name);
00853       /* XXX we could default to 'dsp' perhaps ? */
00854       return NULL;
00855    }
00856    if ((format & AST_FORMAT_SLINEAR) == 0) {
00857       ast_log(LOG_NOTICE, "Format %s unsupported\n", ast_getformatname_multiple(buf, sizeof(buf), format));
00858       return NULL;
00859    }
00860    if (o->owner) {
00861       ast_log(LOG_NOTICE, "Already have a call (chan %p) on the OSS channel\n", o->owner);
00862       *cause = AST_CAUSE_BUSY;
00863       return NULL;
00864    }
00865    c = oss_new(o, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
00866    if (c == NULL) {
00867       ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
00868       return NULL;
00869    }
00870    return c;
00871 }

static int oss_text ( struct ast_channel c,
const char *  text 
) [static]

Definition at line 584 of file chan_oss.c.

References ast_verbose.

00585 {
00586    /* print received messages */
00587    ast_verbose(" << Console Received text %s >> \n", text);
00588    return 0;
00589 }

static int oss_write ( struct ast_channel chan,
struct ast_frame f 
) [static]

used for data coming from the network

Definition at line 665 of file chan_oss.c.

References ast_frame::data, ast_frame::datalen, chan_oss_pvt::oss_write_buf, chan_oss_pvt::oss_write_dst, ast_frame::ptr, soundcard_writeframe(), and ast_channel::tech_pvt.

00666 {
00667    int src;
00668    struct chan_oss_pvt *o = c->tech_pvt;
00669 
00670    /*
00671     * we could receive a block which is not a multiple of our
00672     * FRAME_SIZE, so buffer it locally and write to the device
00673     * in FRAME_SIZE chunks.
00674     * Keep the residue stored for future use.
00675     */
00676    src = 0;             /* read position into f->data */
00677    while (src < f->datalen) {
00678       /* Compute spare room in the buffer */
00679       int l = sizeof(o->oss_write_buf) - o->oss_write_dst;
00680 
00681       if (f->datalen - src >= l) {  /* enough to fill a frame */
00682          memcpy(o->oss_write_buf + o->oss_write_dst, f->data.ptr + src, l);
00683          soundcard_writeframe(o, (short *) o->oss_write_buf);
00684          src += l;
00685          o->oss_write_dst = 0;
00686       } else {          /* copy residue */
00687          l = f->datalen - src;
00688          memcpy(o->oss_write_buf + o->oss_write_dst, f->data.ptr + src, l);
00689          src += l;         /* but really, we are done */
00690          o->oss_write_dst += l;
00691       }
00692    }
00693    return 0;
00694 }

static int setformat ( struct chan_oss_pvt o,
int  mode 
) [static]

reset and close the device if opened, then open and initialize it in the desired mode, trigger reads and writes so we can start using it.

Definition at line 472 of file chan_oss.c.

References ast_channel_set_fd(), ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, DEFAULT_SAMPLE_RATE, chan_oss_pvt::device, chan_oss_pvt::duplex, errno, chan_oss_pvt::frags, chan_oss_pvt::lastopen, LOG_WARNING, O_CLOSE, chan_oss_pvt::owner, chan_oss_pvt::sounddev, WARN_frag, WARN_speed, and chan_oss_pvt::warned.

Referenced by console_hangup(), oss_hangup(), oss_new(), soundcard_writeframe(), and store_config().

00473 {
00474    int fmt, desired, res, fd;
00475 
00476    if (o->sounddev >= 0) {
00477       ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
00478       close(o->sounddev);
00479       o->duplex = M_UNSET;
00480       o->sounddev = -1;
00481    }
00482    if (mode == O_CLOSE)    /* we are done */
00483       return 0;
00484    if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000)
00485       return -1;           /* don't open too often */
00486    o->lastopen = ast_tvnow();
00487    fd = o->sounddev = open(o->device, mode | O_NONBLOCK);
00488    if (fd < 0) {
00489       ast_log(LOG_WARNING, "Unable to re-open DSP device %s: %s\n", o->device, strerror(errno));
00490       return -1;
00491    }
00492    if (o->owner)
00493       ast_channel_set_fd(o->owner, 0, fd);
00494 
00495 #if __BYTE_ORDER == __LITTLE_ENDIAN
00496    fmt = AFMT_S16_LE;
00497 #else
00498    fmt = AFMT_S16_BE;
00499 #endif
00500    res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
00501    if (res < 0) {
00502       ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
00503       return -1;
00504    }
00505    switch (mode) {
00506    case O_RDWR:
00507       res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
00508       /* Check to see if duplex set (FreeBSD Bug) */
00509       res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
00510       if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
00511          ast_verb(2, "Console is full duplex\n");
00512          o->duplex = M_FULL;
00513       };
00514       break;
00515 
00516    case O_WRONLY:
00517       o->duplex = M_WRITE;
00518       break;
00519 
00520    case O_RDONLY:
00521       o->duplex = M_READ;
00522       break;
00523    }
00524 
00525    fmt = 0;
00526    res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
00527    if (res < 0) {
00528       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00529       return -1;
00530    }
00531    fmt = desired = DEFAULT_SAMPLE_RATE;   /* 8000 Hz desired */
00532    res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
00533 
00534    if (res < 0) {
00535       ast_log(LOG_WARNING, "Failed to set sample rate to %d\n", desired);
00536       return -1;
00537    }
00538    if (fmt != desired) {
00539       if (!(o->warned & WARN_speed)) {
00540          ast_log(LOG_WARNING,
00541              "Requested %d Hz, got %d Hz -- sound may be choppy\n",
00542              desired, fmt);
00543          o->warned |= WARN_speed;
00544       }
00545    }
00546    /*
00547     * on Freebsd, SETFRAGMENT does not work very well on some cards.
00548     * Default to use 256 bytes, let the user override
00549     */
00550    if (o->frags) {
00551       fmt = o->frags;
00552       res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
00553       if (res < 0) {
00554          if (!(o->warned & WARN_frag)) {
00555             ast_log(LOG_WARNING,
00556                "Unable to set fragment size -- sound may be choppy\n");
00557             o->warned |= WARN_frag;
00558          }
00559       }
00560    }
00561    /* on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */
00562    res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
00563    res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
00564    /* it may fail if we are in half duplex, never mind */
00565    return 0;
00566 }

static int soundcard_writeframe ( struct chan_oss_pvt o,
short *  data 
) [static]

Write an exactly FRAME_SIZE sized frame

Definition at line 443 of file chan_oss.c.

References ast_log(), FRAME_SIZE, LOG_WARNING, chan_oss_pvt::queuesize, setformat(), chan_oss_pvt::sounddev, used_blocks(), and chan_oss_pvt::w_errors.

Referenced by oss_write().

00444 {
00445    int res;
00446 
00447    if (o->sounddev < 0)
00448       setformat(o, O_RDWR);
00449    if (o->sounddev < 0)
00450       return 0;            /* not fatal */
00451    /*
00452     * Nothing complex to manage the audio device queue.
00453     * If the buffer is full just drop the extra, otherwise write.
00454     * XXX in some cases it might be useful to write anyways after
00455     * a number of failures, to restart the output chain.
00456     */
00457    res = used_blocks(o);
00458    if (res > o->queuesize) {  /* no room to write a block */
00459       if (o->w_errors++ == 0 && (oss_debug & 0x4))
00460          ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);
00461       return 0;
00462    }
00463    o->w_errors = 0;
00464    return write(o->sounddev, (void *)data, FRAME_SIZE * 2);
00465 }

static void store_boost ( struct chan_oss_pvt o,
const char *  s 
) [static]

store the boost factor

Definition at line 1246 of file chan_oss.c.

References ast_log(), chan_oss_pvt::boost, BOOST_MAX, BOOST_SCALE, and LOG_WARNING.

Referenced by console_boost(), and store_config_core().

01247 {
01248    double boost = 0;
01249    if (sscanf(s, "%30lf", &boost) != 1) {
01250       ast_log(LOG_WARNING, "invalid boost <%s>\n", s);
01251       return;
01252    }
01253    if (boost < -BOOST_MAX) {
01254       ast_log(LOG_WARNING, "boost %s too small, using %d\n", s, -BOOST_MAX);
01255       boost = -BOOST_MAX;
01256    } else if (boost > BOOST_MAX) {
01257       ast_log(LOG_WARNING, "boost %s too large, using %d\n", s, BOOST_MAX);
01258       boost = BOOST_MAX;
01259    }
01260    boost = exp(log(10) * boost / 20) * BOOST_SCALE;
01261    o->boost = boost;
01262    ast_log(LOG_WARNING, "setting boost %s to %d\n", s, o->boost);
01263 }

static void store_callerid ( struct chan_oss_pvt o,
const char *  s 
) [static]

store the callerid components

Definition at line 1325 of file chan_oss.c.

References ast_callerid_split(), chan_oss_pvt::cid_name, and chan_oss_pvt::cid_num.

Referenced by store_config_core().

01326 {
01327    ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
01328 }

static struct chan_oss_pvt* store_config ( struct ast_config cfg,
char *  ctg 
) [static, read]

grab fields from the config file, init the descriptor and open the device.

Definition at line 1361 of file chan_oss.c.

References ast_asprintf, ast_calloc, ast_copy_string(), ast_free, ast_log(), ast_strdup, ast_strlen_zero(), ast_tvnow(), ast_variable_browse(), ast_verb, console_video_start(), DEV_DSP, chan_oss_pvt::device, chan_oss_pvt::duplex, chan_oss_pvt::env, errno, get_gui_startup(), chan_oss_pvt::lastopen, LOG_WARNING, chan_oss_pvt::M_FULL, chan_oss_pvt::mixer_cmd, chan_oss_pvt::mohinterpret, ast_variable::name, chan_oss_pvt::name, chan_oss_pvt::next, ast_variable::next, setformat(), store_config_core(), and ast_variable::value.

Referenced by load_module().

01362 {
01363    struct ast_variable *v;
01364    struct chan_oss_pvt *o;
01365 
01366    if (ctg == NULL) {
01367       o = &oss_default;
01368       ctg = "general";
01369    } else {
01370       if (!(o = ast_calloc(1, sizeof(*o))))
01371          return NULL;
01372       *o = oss_default;
01373       /* "general" is also the default thing */
01374       if (strcmp(ctg, "general") == 0) {
01375          o->name = ast_strdup("dsp");
01376          oss_active = o->name;
01377          goto openit;
01378       }
01379       o->name = ast_strdup(ctg);
01380    }
01381 
01382    strcpy(o->mohinterpret, "default");
01383 
01384    o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */
01385    /* fill other fields from configuration */
01386    for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
01387       store_config_core(o, v->name, v->value);
01388    }
01389    if (ast_strlen_zero(o->device))
01390       ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
01391    if (o->mixer_cmd) {
01392       char *cmd;
01393 
01394       if (ast_asprintf(&cmd, "mixer %s", o->mixer_cmd) >= 0) {
01395          ast_log(LOG_WARNING, "running [%s]\n", cmd);
01396          if (system(cmd) < 0) {
01397             ast_log(LOG_WARNING, "system() failed: %s\n", strerror(errno));
01398          }
01399          ast_free(cmd);
01400       }
01401    }
01402 
01403    /* if the config file requested to start the GUI, do it */
01404    if (get_gui_startup(o->env))
01405       console_video_start(o->env, NULL);
01406 
01407    if (o == &oss_default)     /* we are done with the default */
01408       return NULL;
01409 
01410 openit:
01411 #ifdef TRYOPEN
01412    if (setformat(o, O_RDWR) < 0) {  /* open device */
01413       ast_verb(1, "Device %s not detected\n", ctg);
01414       ast_verb(1, "Turn off OSS support by adding " "'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
01415       goto error;
01416    }
01417    if (o->duplex != M_FULL)
01418       ast_log(LOG_WARNING, "XXX I don't work right with non " "full-duplex sound cards XXX\n");
01419 #endif /* TRYOPEN */
01420 
01421    /* link into list of devices */
01422    if (o != &oss_default) {
01423       o->next = oss_default.next;
01424       oss_default.next = o;
01425    }
01426    return o;
01427 
01428 #ifdef TRYOPEN
01429 error:
01430    if (o != &oss_default)
01431       ast_free(o);
01432    return NULL;
01433 #endif
01434 }

static void store_config_core ( struct chan_oss_pvt o,
const char *  var,
const char *  value 
) [static]

Definition at line 1330 of file chan_oss.c.

References ast_jb_read_conf(), chan_oss_pvt::autoanswer, chan_oss_pvt::autohangup, console_video_config(), chan_oss_pvt::ctx, CV_BOOL, CV_END, CV_F, CV_START, CV_STR, CV_UINT, chan_oss_pvt::device, chan_oss_pvt::env, chan_oss_pvt::ext, chan_oss_pvt::frags, global_jbconf, chan_oss_pvt::language, chan_oss_pvt::mohinterpret, chan_oss_pvt::overridecontext, chan_oss_pvt::queuesize, store_boost(), store_callerid(), and store_mixer().

Referenced by console_cmd(), and store_config().

01331 {
01332    CV_START(var, value);
01333 
01334    /* handle jb conf */
01335    if (!ast_jb_read_conf(&global_jbconf, var, value))
01336       return;
01337 
01338    if (!console_video_config(&o->env, var, value))
01339       return;  /* matched there */
01340    CV_BOOL("autoanswer", o->autoanswer);
01341    CV_BOOL("autohangup", o->autohangup);
01342    CV_BOOL("overridecontext", o->overridecontext);
01343    CV_STR("device", o->device);
01344    CV_UINT("frags", o->frags);
01345    CV_UINT("debug", oss_debug);
01346    CV_UINT("queuesize", o->queuesize);
01347    CV_STR("context", o->ctx);
01348    CV_STR("language", o->language);
01349    CV_STR("mohinterpret", o->mohinterpret);
01350    CV_STR("extension", o->ext);
01351    CV_F("mixer", store_mixer(o, value));
01352    CV_F("callerid", store_callerid(o, value))  ;
01353    CV_F("boost", store_boost(o, value));
01354 
01355    CV_END;
01356 }

static void store_mixer ( struct chan_oss_pvt o,
const char *  s 
) [static]

store the mixer argument from the config file, filtering possibly invalid or dangerous values (the string is used as argument for system("mixer %s")

Definition at line 1306 of file chan_oss.c.

References ast_free, ast_log(), ast_strdup, LOG_WARNING, and chan_oss_pvt::mixer_cmd.

Referenced by store_config_core().

01307 {
01308    int i;
01309 
01310    for (i = 0; i < strlen(s); i++) {
01311       if (!isalnum(s[i]) && strchr(" \t-/", s[i]) == NULL) {
01312          ast_log(LOG_WARNING, "Suspect char %c in mixer cmd, ignoring:\n\t%s\n", s[i], s);
01313          return;
01314       }
01315    }
01316    if (o->mixer_cmd)
01317       ast_free(o->mixer_cmd);
01318    o->mixer_cmd = ast_strdup(s);
01319    ast_log(LOG_WARNING, "setting mixer %s\n", s);
01320 }

static int unload_module ( void   )  [static]

Definition at line 1480 of file chan_oss.c.

References ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_free, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, chan_oss_pvt::name, chan_oss_pvt::next, chan_oss_pvt::owner, and chan_oss_pvt::sounddev.

01481 {
01482    struct chan_oss_pvt *o, *next;
01483 
01484    ast_channel_unregister(&oss_tech);
01485    ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss));
01486 
01487    o = oss_default.next;
01488    while (o) {
01489       close(o->sounddev);
01490       if (o->owner)
01491          ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
01492       if (o->owner)
01493          return -1;
01494       next = o->next;
01495       ast_free(o->name);
01496       ast_free(o);
01497       o = next;
01498    }
01499    return 0;
01500 }

static int used_blocks ( struct chan_oss_pvt o  )  [static]

Returns the number of blocks used in the audio output channel.

Definition at line 421 of file chan_oss.c.

References ast_log(), LOG_WARNING, chan_oss_pvt::sounddev, chan_oss_pvt::total_blocks, WARN_used_blocks, and chan_oss_pvt::warned.

Referenced by soundcard_writeframe().

00422 {
00423    struct audio_buf_info info;
00424 
00425    if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
00426       if (!(o->warned & WARN_used_blocks)) {
00427          ast_log(LOG_WARNING, "Error reading output space\n");
00428          o->warned |= WARN_used_blocks;
00429       }
00430       return 1;
00431    }
00432 
00433    if (o->total_blocks == 0) {
00434       if (0)               /* debugging */
00435          ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);
00436       o->total_blocks = info.fragments;
00437    }
00438 
00439    return o->total_blocks - info.fragments;
00440 }


Variable Documentation

struct ast_cli_entry cli_oss[] [static]

Definition at line 1287 of file chan_oss.c.

char* config = "oss.conf" [static]

Definition at line 235 of file chan_oss.c.

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Note:
Values shown here match the defaults shown in oss.conf.sample

Definition at line 71 of file chan_oss.c.

struct ast_jb_conf global_jbconf [static]

Definition at line 79 of file chan_oss.c.

Referenced by load_module(), oss_new(), and store_config_core().

char* oss_active [static]

the active device

Definition at line 306 of file chan_oss.c.

int oss_debug [static]

Definition at line 237 of file chan_oss.c.

struct chan_oss_pvt oss_default [static]

Definition at line 314 of file chan_oss.c.

struct ast_channel_tech oss_tech [static]

Definition at line 346 of file chan_oss.c.

char tdesc[] = "OSS Console Channel Driver" [static]

Definition at line 343 of file chan_oss.c.


Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1