Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:11 2007

Asterisk developer's documentation :: Codename Pineapple


chan_oss.c File Reference


Detailed Description

Channel driver for OSS sound cards.

Author:
Mark Spencer <markster@digium.com>

Luigi Rizzo

See also

Definition in file chan_oss.c.

#include "asterisk.h"
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/time.h>
#include <stdlib.h>
#include <errno.h>
#include <soundcard.h>
#include "asterisk/lock.h"
#include "asterisk/frame.h"
#include "asterisk/logger.h"
#include "asterisk/callerid.h"
#include "asterisk/channel.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/endian.h"
#include "asterisk/stringfields.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/musiconhold.h"
#include "asterisk/app.h"
#include "busy.h"
#include "ringtone.h"
#include "ring10.h"
#include "answer.h"

Include dependency graph for chan_oss.c:

Go to the source code of this file.

Data Structures

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

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 M_BOOL(tag, dst)   M_F(tag, (dst) = ast_true(__val) )
#define M_END(x)   x;
#define M_F(tag, f)   if (!strcasecmp((__s), tag)) { f; } else
#define M_START(var, val)   char *__s = var; char *__val = val;
#define M_STR(tag, dst)   M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
#define M_UINT(tag, dst)   M_F(tag, (dst) = strtoul(__val, NULL, 0) )
#define MAX(a, b)   ((a) > (b) ? (a) : (b))
#define MIN(a, b)   ((a) < (b) ? (a) : (b))
#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 int console_active (int fd, int argc, char *argv[])
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_dial (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 int console_transfer (int fd, int argc, char *argv[])
static int do_boost (int fd, int argc, char *argv[])
static struct chan_oss_pvtfind_desc (char *dev)
 returns a pointer to the descriptor with the given name
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)
 allocate a new channel.
static struct ast_frameoss_read (struct ast_channel *chan)
static struct ast_channeloss_request (const char *type, int format, 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 void ring (struct chan_oss_pvt *o, int x)
 Play ringtone 'x' on device 'o'.
static void send_sound (struct chan_oss_pvt *o)
 Handler for 'sound writable' events from the sound thread.
static int setformat (struct chan_oss_pvt *o, int mode)
static void * sound_thread (void *arg)
static int soundcard_writeframe (struct chan_oss_pvt *o, short *data)
static void store_boost (struct chan_oss_pvt *o, char *s)
 store the boost factor
static void store_callerid (struct chan_oss_pvt *o, char *s)
static struct chan_oss_pvtstore_config (struct ast_config *cfg, char *ctg)
static void store_mixer (struct chan_oss_pvt *o, 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 const char active_usage []
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 const struct ast_channel_tech oss_tech
static struct sound sounds []
static char tdesc [] = "OSS Console Channel Driver"
static const char transfer_usage []


Define Documentation

#define BOOST_MAX   40
 

slightly less than 7 bits

Definition at line 362 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 361 of file chan_oss.c.

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

#define DEV_DSP   "/dev/dsp"
 

Definition at line 275 of file chan_oss.c.

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

Definition at line 258 of file chan_oss.c.

#define FRAME_SIZE   160
 

Definition at line 252 of file chan_oss.c.

#define M_BOOL tag,
dst   )     M_F(tag, (dst) = ast_true(__val) )
 

Definition at line 218 of file chan_oss.c.

Referenced by store_config().

#define M_END  )     x;
 

Definition at line 216 of file chan_oss.c.

Referenced by store_config().

#define M_F tag,
 )     if (!strcasecmp((__s), tag)) { f; } else
 

Definition at line 217 of file chan_oss.c.

Referenced by store_config().

#define M_START var,
val   )     char *__s = var; char *__val = val;
 

Definition at line 214 of file chan_oss.c.

Referenced by store_config().

#define M_STR tag,
dst   )     M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))
 

Definition at line 220 of file chan_oss.c.

Referenced by store_config().

#define M_UINT tag,
dst   )     M_F(tag, (dst) = strtoul(__val, NULL, 0) )
 

Definition at line 219 of file chan_oss.c.

Referenced by store_config().

#define MAX a,
 )     ((a) > (b) ? (a) : (b))
 

Definition at line 282 of file chan_oss.c.

#define MIN a,
 )     ((a) < (b) ? (a) : (b))
 

Definition at line 279 of file chan_oss.c.

#define O_CLOSE   0x444
 

Definition at line 270 of file chan_oss.c.

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

#define QUEUE_SIZE   10
 

Definition at line 253 of file chan_oss.c.

#define TEXT_SIZE   256
 

Definition at line 265 of file chan_oss.c.

Referenced by console_sendtext().

#define WARN_frag   4
 

Definition at line 351 of file chan_oss.c.

Referenced by setformat().

#define WARN_speed   2
 

Definition at line 350 of file chan_oss.c.

Referenced by setformat().

#define WARN_used_blocks   1
 

Definition at line 349 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 466 of file chan_oss.c.

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

Referenced by console_transfer().

00467 {
00468    struct chan_oss_pvt *o = find_desc(oss_active);
00469 
00470    if (ext == NULL || ctx == NULL)
00471       return NULL;         /* error */
00472 
00473    *ext = *ctx = NULL;
00474 
00475    if (src && *src != '\0')
00476       *ext = ast_strdup(src);
00477 
00478    if (*ext == NULL)
00479       return NULL;
00480 
00481    if (!o->overridecontext) {
00482       /* parse from the right */
00483       *ctx = strrchr(*ext, '@');
00484       if (*ctx)
00485          *(*ctx)++ = '\0';
00486    }
00487 
00488    return *ext;
00489 }

AST_MODULE_INFO_STANDARD ASTERISK_GPL_KEY  ,
"OSS Console Channel Driver" 
 

static int console_active int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 1378 of file chan_oss.c.

References ast_cli(), find_desc(), chan_oss_pvt::name, chan_oss_pvt::next, oss_default, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01379 {
01380    if (argc == 2)
01381       ast_cli(fd, "active console is [%s]\n", oss_active);
01382    else if (argc != 3)
01383       return RESULT_SHOWUSAGE;
01384    else {
01385       struct chan_oss_pvt *o;
01386       if (strcmp(argv[2], "show") == 0) {
01387          for (o = oss_default.next; o; o = o->next)
01388             ast_cli(fd, "device [%s] exists\n", o->name);
01389          return RESULT_SUCCESS;
01390       }
01391       o = find_desc(argv[2]);
01392       if (o == NULL)
01393          ast_cli(fd, "No device [%s] exists\n", argv[2]);
01394       else
01395          oss_active = o->name;
01396    }
01397    return RESULT_SUCCESS;
01398 }

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 1142 of file chan_oss.c.

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

01143 {
01144    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
01145    struct chan_oss_pvt *o = find_desc(oss_active);
01146 
01147    switch (cmd) {
01148    case CLI_INIT:
01149       e->command = "console answer";
01150       e->usage =
01151          "Usage: console answer\n"
01152          "       Answers an incoming call on the console (OSS) channel.\n";
01153       return NULL;
01154 
01155    case CLI_GENERATE:
01156       return NULL;   /* no completion */
01157    }
01158    if (a->argc != e->args)
01159       return CLI_SHOWUSAGE;
01160    if (!o->owner) {
01161       ast_cli(a->fd, "No one is calling us\n");
01162       return CLI_FAILURE;
01163    }
01164    o->hookstate = 1;
01165    o->cursound = -1;
01166    o->nosound = 0;
01167    ast_queue_frame(o->owner, &f);
01168    return CLI_SUCCESS;
01169 }

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

Definition at line 1101 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.

01102 {
01103    struct chan_oss_pvt *o = find_desc(oss_active);
01104 
01105    switch (cmd) {
01106    case CLI_INIT:
01107       e->command = "console autoanswer [on|off]";
01108       e->usage =
01109          "Usage: console autoanswer [on|off]\n"
01110          "       Enables or disables autoanswer feature.  If used without\n"
01111          "       argument, displays the current on/off status of autoanswer.\n"
01112          "       The default value of autoanswer is in 'oss.conf'.\n";
01113       return NULL;
01114 
01115    case CLI_GENERATE:
01116       return NULL;
01117    }
01118 
01119    if (a->argc == e->args - 1) {
01120       ast_cli(a->fd, "Auto answer is %s.\n", o->autoanswer ? "on" : "off");
01121       return CLI_SUCCESS;
01122    }
01123    if (a->argc != e->args)
01124       return CLI_SHOWUSAGE;
01125    if (o == NULL) {
01126       ast_log(LOG_WARNING, "Cannot find device %s (should not happen!)\n",
01127           oss_active);
01128       return CLI_FAILURE;
01129    }
01130    if (!strcasecmp(a->argv[e->args-1], "on"))
01131       o->autoanswer = 1;
01132    else if (!strcasecmp(a->argv[e->args - 1], "off"))
01133       o->autoanswer = 0;
01134    else
01135       return CLI_SHOWUSAGE;
01136    return CLI_SUCCESS;
01137 }

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

Definition at line 1267 of file chan_oss.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), AST_FRAME_DTMF, 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::owner, s, ast_frame::subclass, and ast_cli_entry::usage.

01268 {
01269    char *s = NULL, *mye = NULL, *myc = NULL;
01270    struct chan_oss_pvt *o = find_desc(oss_active);
01271 
01272    if (cmd == CLI_INIT) {
01273       e->command = "console dial";
01274       e->usage =
01275          "Usage: console dial [extension[@context]]\n"
01276          "       Dials a given extension (and context if specified)\n";
01277       return NULL;
01278    } else if (cmd == CLI_GENERATE)
01279       return NULL;
01280 
01281    if (a->argc > e->args + 1)
01282       return CLI_SHOWUSAGE;
01283    if (o->owner) {   /* already in a call */
01284       int i;
01285       struct ast_frame f = { AST_FRAME_DTMF, 0 };
01286 
01287       if (a->argc == e->args) {  /* argument is mandatory here */
01288          ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
01289          return CLI_FAILURE;
01290       }
01291       s = a->argv[e->args];
01292       /* send the string one char at a time */
01293       for (i = 0; i < strlen(s); i++) {
01294          f.subclass = s[i];
01295          ast_queue_frame(o->owner, &f);
01296       }
01297       return CLI_SUCCESS;
01298    }
01299    /* if we have an argument split it into extension and context */
01300    if (a->argc == e->args + 1)
01301       s = ast_ext_ctx(a->argv[e->args], &mye, &myc);
01302    /* supply default values if needed */
01303    if (mye == NULL)
01304       mye = o->ext;
01305    if (myc == NULL)
01306       myc = o->ctx;
01307    if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
01308       o->hookstate = 1;
01309       oss_new(o, mye, myc, AST_STATE_RINGING);
01310    } else
01311       ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
01312    if (s)
01313       free(s);
01314    return CLI_SUCCESS;
01315 }

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

Definition at line 1239 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, chan_oss_pvt::cursound, ast_cli_args::fd, find_desc(), chan_oss_pvt::hookstate, chan_oss_pvt::nosound, chan_oss_pvt::owner, and ast_cli_entry::usage.

01240 {
01241    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH };
01242    struct chan_oss_pvt *o = find_desc(oss_active);
01243 
01244    if (cmd == CLI_INIT) {
01245       e->command = "console flash";
01246       e->usage =
01247          "Usage: console flash\n"
01248          "       Flashes the call currently placed on the console.\n";
01249       return NULL;
01250    } else if (cmd == CLI_GENERATE)
01251       return NULL;
01252 
01253    if (a->argc != e->args)
01254       return CLI_SHOWUSAGE;
01255    o->cursound = -1;
01256    o->nosound = 0;            /* when cursound is -1 nosound must be 0 */
01257    if (!o->owner) {        /* XXX maybe !o->hookstate too ? */
01258       ast_cli(a->fd, "No call to flash\n");
01259       return CLI_FAILURE;
01260    }
01261    o->hookstate = 0;
01262    if (o->owner)           /* XXX must be true, right ? */
01263       ast_queue_frame(o->owner, &f);
01264    return CLI_SUCCESS;
01265 }

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

Definition at line 1211 of file chan_oss.c.

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

01212 {
01213    struct chan_oss_pvt *o = find_desc(oss_active);
01214 
01215    if (cmd == CLI_INIT) {
01216       e->command = "console hangup";
01217       e->usage =
01218          "Usage: console hangup\n"
01219          "       Hangs up any call currently placed on the console.\n";
01220       return NULL;
01221    } else if (cmd == CLI_GENERATE)
01222       return NULL;
01223 
01224    if (a->argc != e->args)
01225       return CLI_SHOWUSAGE;
01226    o->cursound = -1;
01227    o->nosound = 0;
01228    if (!o->owner && !o->hookstate) { /* XXX maybe only one ? */
01229       ast_cli(a->fd, "No call to hang up\n");
01230       return CLI_FAILURE;
01231    }
01232    o->hookstate = 0;
01233    if (o->owner)
01234       ast_queue_hangup(o->owner);
01235    setformat(o, O_CLOSE);
01236    return CLI_SUCCESS;
01237 }

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

Definition at line 1317 of file chan_oss.c.

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

01318 {
01319    struct chan_oss_pvt *o = find_desc(oss_active);
01320    char *s;
01321    
01322    if (cmd == CLI_INIT) {
01323       e->command = "console {mute|unmute}";
01324       e->usage =
01325          "Usage: console {mute|unmute}\n"
01326          "       Mute/unmute the microphone.\n";
01327       return NULL;
01328    } else if (cmd == CLI_GENERATE)
01329       return NULL;
01330 
01331    if (a->argc != e->args)
01332       return CLI_SHOWUSAGE;
01333    s = a->argv[e->args-1];
01334    if (!strcasecmp(s, "mute"))
01335       o->mute = 1;
01336    else if (!strcasecmp(s, "unmute"))
01337       o->mute = 0;
01338    else
01339       return CLI_SHOWUSAGE;
01340    return CLI_SUCCESS;
01341 }

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 1177 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, chan_oss_pvt::owner, ast_frame::subclass, TEXT_SIZE, and ast_cli_entry::usage.

01178 {
01179    struct chan_oss_pvt *o = find_desc(oss_active);
01180    char buf[TEXT_SIZE];
01181 
01182    if (cmd == CLI_INIT) {
01183       e->command = "console send text";
01184       e->usage =
01185          "Usage: console send text <message>\n"
01186          "       Sends a text message for display on the remote terminal.\n";
01187       return NULL;
01188    } else if (cmd == CLI_GENERATE)
01189       return NULL;
01190 
01191    if (a->argc < e->args + 1)
01192       return CLI_SHOWUSAGE;
01193    if (!o->owner) {
01194       ast_cli(a->fd, "Not in a call\n");
01195       return CLI_FAILURE;
01196    }
01197    ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01198    if (!ast_strlen_zero(buf)) {
01199       struct ast_frame f = { 0, };
01200       int i = strlen(buf);
01201       buf[i] = '\n';
01202       f.frametype = AST_FRAME_TEXT;
01203       f.subclass = 0;
01204       f.data = buf;
01205       f.datalen = i + 1;
01206       ast_queue_frame(o->owner, &f);
01207    }
01208    return CLI_SUCCESS;
01209 }

static int console_transfer int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 1343 of file chan_oss.c.

References ast_async_goto(), ast_bridged_channel(), ast_cli(), ast_exists_extension(), ast_ext_ctx(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ext, find_desc(), free, chan_oss_pvt::owner, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01344 {
01345    struct chan_oss_pvt *o = find_desc(oss_active);
01346    struct ast_channel *b = NULL;
01347    char *tmp, *ext, *ctx;
01348 
01349    if (argc != 3)
01350       return RESULT_SHOWUSAGE;
01351    if (o == NULL)
01352       return RESULT_FAILURE;
01353    if (o->owner == NULL || (b = ast_bridged_channel(o->owner)) == NULL) {
01354       ast_cli(fd, "There is no call to transfer\n");
01355       return RESULT_SUCCESS;
01356    }
01357 
01358    tmp = ast_ext_ctx(argv[2], &ext, &ctx);
01359    if (ctx == NULL)        /* supply default context if needed */
01360       ctx = o->owner->context;
01361    if (!ast_exists_extension(b, ctx, ext, 1, b->cid.cid_num))
01362       ast_cli(fd, "No such extension exists\n");
01363    else {
01364       ast_cli(fd, "Whee, transferring %s to %s@%s.\n", b->name, ext, ctx);
01365       if (ast_async_goto(b, ctx, ext, 1))
01366          ast_cli(fd, "Failed to transfer :(\n");
01367    }
01368    if (tmp)
01369       free(tmp);
01370    return RESULT_SUCCESS;
01371 }

static int do_boost int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 1428 of file chan_oss.c.

References ast_cli(), chan_oss_pvt::boost, BOOST_SCALE, find_desc(), RESULT_SUCCESS, and store_boost().

01429 {
01430    struct chan_oss_pvt *o = find_desc(oss_active);
01431 
01432    if (argc == 2)
01433       ast_cli(fd, "boost currently %5.1f\n", 20 * log10(((double) o->boost / (double) BOOST_SCALE)));
01434    else if (argc == 3)
01435       store_boost(o, argv[2]);
01436    return RESULT_SUCCESS;
01437 }

static struct chan_oss_pvt* find_desc char *  dev  )  [static]
 

returns a pointer to the descriptor with the given name

Definition at line 440 of file chan_oss.c.

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

Referenced by ast_ext_ctx(), console_active(), console_answer(), console_autoanswer(), console_dial(), console_flash(), console_hangup(), console_mute(), console_sendtext(), console_transfer(), do_boost(), load_module(), and oss_request().

00441 {
00442    struct chan_oss_pvt *o = NULL;
00443 
00444    if (!dev)
00445       ast_log(LOG_WARNING, "null dev\n");
00446 
00447    for (o = oss_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next);
00448 
00449    if (!o)
00450       ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--");
00451 
00452    return o;
00453 }

static int load_module void   )  [static]
 

Definition at line 1585 of file chan_oss.c.

References 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, cli_oss, default_jbconf, find_desc(), global_jbconf, LOG_ERROR, LOG_NOTICE, oss_tech, and store_config().

01586 {
01587    struct ast_config *cfg = NULL;
01588    char *ctg = NULL;
01589 
01590    /* Copy the default jb config over global_jbconf */
01591    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01592 
01593    /* load config file */
01594    if (!(cfg = ast_config_load(config))) {
01595       ast_log(LOG_NOTICE, "Unable to load config %s\n", config);
01596       return AST_MODULE_LOAD_DECLINE;
01597    }
01598 
01599    do {
01600       store_config(cfg, ctg);
01601    } while ( (ctg = ast_category_browse(cfg, ctg)) != NULL);
01602 
01603    ast_config_destroy(cfg);
01604 
01605    if (find_desc(oss_active) == NULL) {
01606       ast_log(LOG_NOTICE, "Device %s not found\n", oss_active);
01607       /* XXX we could default to 'dsp' perhaps ? */
01608       /* XXX should cleanup allocated memory etc. */
01609       return AST_MODULE_LOAD_FAILURE;
01610    }
01611 
01612    if (ast_channel_register(&oss_tech)) {
01613       ast_log(LOG_ERROR, "Unable to register channel type 'OSS'\n");
01614       return AST_MODULE_LOAD_FAILURE;
01615    }
01616 
01617    ast_cli_register_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry));
01618 
01619    return AST_MODULE_LOAD_SUCCESS;
01620 }

static int oss_answer struct ast_channel c  )  [static]
 

remote side answered the phone

Definition at line 844 of file chan_oss.c.

References AST_CONTROL_ANSWER, ast_setstate(), AST_STATE_UP, ast_verbose(), chan_oss_pvt::cursound, chan_oss_pvt::nosound, ring(), and ast_channel::tech_pvt.

00845 {
00846    struct chan_oss_pvt *o = c->tech_pvt;
00847 
00848    ast_verbose(" << Console call has been answered >> \n");
00849 #if 0
00850    /* play an answer tone (XXX do we really need it ?) */
00851    ring(o, AST_CONTROL_ANSWER);
00852 #endif
00853    ast_setstate(c, AST_STATE_UP);
00854    o->cursound = -1;
00855    o->nosound = 0;
00856    return 0;
00857 }

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 804 of file chan_oss.c.

References AST_APP_ARG, AST_CONTROL_ANSWER, AST_CONTROL_RING, AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, AST_FRAME_CONTROL, AST_NONSTANDARD_APP_ARGS, ast_queue_frame(), ast_strdupa, ast_strlen_zero(), ast_verbose(), chan_oss_pvt::autoanswer, ast_channel::cid, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_frame::frametype, name, parse(), ring(), ast_frame::subclass, and ast_channel::tech_pvt.

00805 {
00806    struct chan_oss_pvt *o = c->tech_pvt;
00807    struct ast_frame f = { 0, };
00808    AST_DECLARE_APP_ARGS(args,
00809       AST_APP_ARG(name);
00810       AST_APP_ARG(flags);
00811    );
00812    char *parse = ast_strdupa(dest);
00813 
00814    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
00815 
00816    ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n", dest, c->cid.cid_dnid, c->cid.cid_rdnis, c->cid.cid_name, c->cid.cid_num);
00817    if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "answer") == 0) {
00818       f.frametype = AST_FRAME_CONTROL;
00819       f.subclass = AST_CONTROL_ANSWER;
00820       ast_queue_frame(c, &f);
00821    } else if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "noanswer") == 0) {
00822       f.frametype = AST_FRAME_CONTROL;
00823       f.subclass = AST_CONTROL_RINGING;
00824       ast_queue_frame(c, &f);
00825       ring(o, AST_CONTROL_RING);
00826    } else if (o->autoanswer) {
00827       ast_verbose(" << Auto-answered >> \n");
00828       f.frametype = AST_FRAME_CONTROL;
00829       f.subclass = AST_CONTROL_ANSWER;
00830       ast_queue_frame(c, &f);
00831    } else {
00832       ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00833       f.frametype = AST_FRAME_CONTROL;
00834       f.subclass = AST_CONTROL_RINGING;
00835       ast_queue_frame(c, &f);
00836       ring(o, AST_CONTROL_RING);
00837    }
00838    return 0;
00839 }

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

Definition at line 774 of file chan_oss.c.

00775 {
00776    return 0;
00777 }

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

Definition at line 779 of file chan_oss.c.

References ast_verbose().

00780 {
00781    /* no better use for received digits than print them */
00782    ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 
00783       digit, duration);
00784    return 0;
00785 }

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

Definition at line 968 of file chan_oss.c.

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

00969 {
00970    struct chan_oss_pvt *o = newchan->tech_pvt;
00971    o->owner = newchan;
00972    return 0;
00973 }

static int oss_hangup struct ast_channel c  )  [static]
 

Definition at line 859 of file chan_oss.c.

References AST_CONTROL_CONGESTION, ast_module_unref(), ast_verbose(), chan_oss_pvt::autoanswer, chan_oss_pvt::autohangup, chan_oss_pvt::cursound, chan_oss_pvt::hookstate, chan_oss_pvt::nosound, O_CLOSE, chan_oss_pvt::owner, ring(), setformat(), and ast_channel::tech_pvt.

00860 {
00861    struct chan_oss_pvt *o = c->tech_pvt;
00862 
00863    o->cursound = -1;
00864    o->nosound = 0;
00865    c->tech_pvt = NULL;
00866    o->owner = NULL;
00867    ast_verbose(" << Hangup on console >> \n");
00868    ast_module_unref(ast_module_info->self);
00869    if (o->hookstate) {
00870       if (o->autoanswer || o->autohangup) {
00871          /* Assume auto-hangup too */
00872          o->hookstate = 0;
00873          setformat(o, O_CLOSE);
00874       } else {
00875          /* Make congestion noise */
00876          ring(o, AST_CONTROL_CONGESTION);
00877       }
00878    }
00879    return 0;
00880 }

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

Definition at line 975 of file chan_oss.c.

References AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_log(), ast_moh_start(), ast_moh_stop(), ast_verbose(), chan_oss_pvt::cursound, LOG_WARNING, chan_oss_pvt::mohinterpret, chan_oss_pvt::nosound, ring(), and ast_channel::tech_pvt.

00976 {
00977    struct chan_oss_pvt *o = c->tech_pvt;
00978    int res = -1;
00979 
00980    switch (cond) {
00981    case AST_CONTROL_BUSY:
00982    case AST_CONTROL_CONGESTION:
00983    case AST_CONTROL_RINGING:
00984       res = cond;
00985       break;
00986 
00987    case -1:
00988       o->cursound = -1;
00989       o->nosound = 0;      /* when cursound is -1 nosound must be 0 */
00990       return 0;
00991 
00992    case AST_CONTROL_VIDUPDATE:
00993       res = -1;
00994       break;
00995 
00996    case AST_CONTROL_HOLD:
00997       ast_verbose(" << Console Has Been Placed on Hold >> \n");
00998       ast_moh_start(c, data, o->mohinterpret);
00999       break;
01000 
01001    case AST_CONTROL_UNHOLD:
01002       ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
01003       ast_moh_stop(c);
01004       break;
01005 
01006    default:
01007       ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
01008       return -1;
01009    }
01010 
01011    if (res > -1)
01012       ring(o, res);
01013 
01014    return 0;
01015 }

static struct ast_channel* oss_new struct chan_oss_pvt o,
char *  ext,
char *  ctx,
int  state
[static]
 

allocate a new channel.

Definition at line 1020 of file chan_oss.c.

References ast_channel_alloc(), AST_FORMAT_SLINEAR, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), AST_STATE_DOWN, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_dnid, ast_callerid::cid_name, chan_oss_pvt::cid_name, ast_callerid::cid_num, chan_oss_pvt::cid_num, ast_channel::context, chan_oss_pvt::device, ast_channel::exten, ast_channel::fds, global_jbconf, language, chan_oss_pvt::language, LOG_WARNING, ast_channel::nativeformats, oss_tech, chan_oss_pvt::owner, ast_channel::readformat, setformat(), chan_oss_pvt::sounddev, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.

Referenced by oss_request().

01021 {
01022    struct ast_channel *c;
01023 
01024    c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "OSS/%s", o->device + 5);
01025    if (c == NULL)
01026       return NULL;
01027    c->tech = &oss_tech;
01028    if (o->sounddev < 0)
01029       setformat(o, O_RDWR);
01030    c->fds[0] = o->sounddev;   /* -1 if device closed, override later */
01031    c->nativeformats = AST_FORMAT_SLINEAR;
01032    c->readformat = AST_FORMAT_SLINEAR;
01033    c->writeformat = AST_FORMAT_SLINEAR;
01034    c->tech_pvt = o;
01035 
01036    if (!ast_strlen_zero(ctx))
01037       ast_copy_string(c->context, ctx, sizeof(c->context));
01038    if (!ast_strlen_zero(ext))
01039       ast_copy_string(c->exten, ext, sizeof(c->exten));
01040    if (!ast_strlen_zero(o->language))
01041       ast_string_field_set(c, language, o->language);
01042    /* Don't use ast_set_callerid() here because it will
01043     * generate a needless NewCallerID event */
01044    c->cid.cid_num = ast_strdup(o->cid_num);
01045    c->cid.cid_ani = ast_strdup(o->cid_num);
01046    c->cid.cid_name = ast_strdup(o->cid_name);
01047    if (!ast_strlen_zero(ext))
01048       c->cid.cid_dnid = ast_strdup(ext);
01049 
01050    o->owner = c;
01051    ast_module_ref(ast_module_info->self);
01052    ast_jb_configure(c, &global_jbconf);
01053    if (state != AST_STATE_DOWN) {
01054       if (ast_pbx_start(c)) {
01055          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", c->name);
01056          ast_hangup(c);
01057          o->owner = c = NULL;
01058          /* XXX what about the channel itself ? */
01059       }
01060    }
01061 
01062    return c;
01063 }

static struct ast_frame * oss_read struct ast_channel chan  )  [static]
 

Definition at line 919 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::data, ast_frame::datalen, FRAME_SIZE, ast_frame::frametype, chan_oss_pvt::mute, chan_oss_pvt::oss_read_buf, oss_tech, 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.

00920 {
00921    int res;
00922    struct chan_oss_pvt *o = c->tech_pvt;
00923    struct ast_frame *f = &o->read_f;
00924 
00925    /* XXX can be simplified returning &ast_null_frame */
00926    /* prepare a NULL frame in case we don't have enough data to return */
00927    bzero(f, sizeof(struct ast_frame));
00928    f->frametype = AST_FRAME_NULL;
00929    f->src = oss_tech.type;
00930 
00931    res = read(o->sounddev, o->oss_read_buf + o->readpos, sizeof(o->oss_read_buf) - o->readpos);
00932    if (res < 0)            /* audio data not ready, return a NULL frame */
00933       return f;
00934 
00935    o->readpos += res;
00936    if (o->readpos < sizeof(o->oss_read_buf)) /* not enough samples */
00937       return f;
00938 
00939    if (o->mute)
00940       return f;
00941 
00942    o->readpos = AST_FRIENDLY_OFFSET;   /* reset read pointer for next frame */
00943    if (c->_state != AST_STATE_UP)   /* drop data if frame is not up */
00944       return f;
00945    /* ok we can build and deliver the frame to the caller */
00946    f->frametype = AST_FRAME_VOICE;
00947    f->subclass = AST_FORMAT_SLINEAR;
00948    f->samples = FRAME_SIZE;
00949    f->datalen = FRAME_SIZE * 2;
00950    f->data = o->oss_read_buf + AST_FRIENDLY_OFFSET;
00951    if (o->boost != BOOST_SCALE) {   /* scale and clip values */
00952       int i, x;
00953       int16_t *p = (int16_t *) f->data;
00954       for (i = 0; i < f->samples; i++) {
00955          x = (p[i] * o->boost) / BOOST_SCALE;
00956          if (x > 32767)
00957             x = 32767;
00958          else if (x < -32768)
00959             x = -32768;
00960          p[i] = x;
00961       }
00962    }
00963 
00964    f->offset = AST_FRIENDLY_OFFSET;
00965    return f;
00966 }

static struct ast_channel * oss_request const char *  type,
int  format,
void *  data,
int *  cause
[static]
 

Definition at line 1065 of file chan_oss.c.

References AST_APP_ARG, AST_CAUSE_BUSY, AST_DECLARE_APP_ARGS, AST_FORMAT_SLINEAR, 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().

01066 {
01067    struct ast_channel *c;
01068    struct chan_oss_pvt *o;
01069    AST_DECLARE_APP_ARGS(args,
01070       AST_APP_ARG(name);
01071       AST_APP_ARG(flags);
01072    );
01073    char *parse = ast_strdupa(data);
01074 
01075    AST_NONSTANDARD_APP_ARGS(args, parse, '/');
01076    o = find_desc(args.name);
01077 
01078    ast_log(LOG_WARNING, "oss_request ty <%s> data 0x%p <%s>\n", type, data, (char *) data);
01079    if (o == NULL) {
01080       ast_log(LOG_NOTICE, "Device %s not found\n", args.name);
01081       /* XXX we could default to 'dsp' perhaps ? */
01082       return NULL;
01083    }
01084    if ((format & AST_FORMAT_SLINEAR) == 0) {
01085       ast_log(LOG_NOTICE, "Format 0x%x unsupported\n", format);
01086       return NULL;
01087    }
01088    if (o->owner) {
01089       ast_log(LOG_NOTICE, "Already have a call (chan %p) on the OSS channel\n", o->owner);
01090       *cause = AST_CAUSE_BUSY;
01091       return NULL;
01092    }
01093    c = oss_new(o, NULL, NULL, AST_STATE_DOWN);
01094    if (c == NULL) {
01095       ast_log(LOG_WARNING, "Unable to create new OSS channel\n");
01096       return NULL;
01097    }
01098    return c;
01099 }

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

Definition at line 787 of file chan_oss.c.

References ast_verbose().

00788 {
00789    /* print received messages */
00790    ast_verbose(" << Console Received text %s >> \n", text);
00791    return 0;
00792 }

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

used for data coming from the network

Definition at line 883 of file chan_oss.c.

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

00884 {
00885    int src;
00886    struct chan_oss_pvt *o = c->tech_pvt;
00887 
00888    /* Immediately return if no sound is enabled */
00889    if (o->nosound)
00890       return 0;
00891    /* Stop any currently playing sound */
00892    o->cursound = -1;
00893    /*
00894     * we could receive a block which is not a multiple of our
00895     * FRAME_SIZE, so buffer it locally and write to the device
00896     * in FRAME_SIZE chunks.
00897     * Keep the residue stored for future use.
00898     */
00899    src = 0;             /* read position into f->data */
00900    while (src < f->datalen) {
00901       /* Compute spare room in the buffer */
00902       int l = sizeof(o->oss_write_buf) - o->oss_write_dst;
00903 
00904       if (f->datalen - src >= l) {  /* enough to fill a frame */
00905          memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);
00906          soundcard_writeframe(o, (short *) o->oss_write_buf);
00907          src += l;
00908          o->oss_write_dst = 0;
00909       } else {          /* copy residue */
00910          l = f->datalen - src;
00911          memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);
00912          src += l;         /* but really, we are done */
00913          o->oss_write_dst += l;
00914       }
00915    }
00916    return 0;
00917 }

static void ring struct chan_oss_pvt o,
int  x
[static]
 

Play ringtone 'x' on device 'o'.

Definition at line 795 of file chan_oss.c.

References chan_oss_pvt::sndcmd.

Referenced by ast_extension_state2(), ind_load_module(), oss_answer(), oss_call(), oss_hangup(), and oss_indicate().

00796 {
00797    write(o->sndcmd[1], &x, sizeof(x));
00798 }

static void send_sound struct chan_oss_pvt o  )  [static]
 

Handler for 'sound writable' events from the sound thread.

Builds a frame from the high level description of the sounds, and passes it to the audio device. The actual sound is made of 1 or more sequences of sound samples (s->datalen, repeated to make s->samplen samples) followed by s->silencelen samples of silence. The position in the sequence is stored in o->sampsent, which goes between 0 .. s->samplen+s->silencelen. In case we fail to write a frame, don't update o->sampsent.

Definition at line 551 of file chan_oss.c.

References ast_log(), chan_oss_pvt::cursound, FRAME_SIZE, LOG_WARNING, MIN, s, chan_oss_pvt::sampsent, and sounds.

00552 {
00553    short myframe[FRAME_SIZE];
00554    int ofs, l, start;
00555    int l_sampsent = o->sampsent;
00556    struct sound *s;
00557 
00558    if (o->cursound < 0)    /* no sound to send */
00559       return;
00560 
00561    s = &sounds[o->cursound];
00562 
00563    for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {
00564       l = s->samplen - l_sampsent;  /* # of available samples */
00565       if (l > 0) {
00566          start = l_sampsent % s->datalen; /* source offset */
00567          l = MIN(l, FRAME_SIZE - ofs); /* don't overflow the frame */
00568          l = MIN(l, s->datalen - start);  /* don't overflow the source */
00569          bcopy(s->data + start, myframe + ofs, l * 2);
00570          if (0)
00571             ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n", l_sampsent, l, s->samplen, ofs);
00572          l_sampsent += l;
00573       } else {          /* end of samples, maybe some silence */
00574          static const short silence[FRAME_SIZE] = { 0, };
00575 
00576          l += s->silencelen;
00577          if (l > 0) {
00578             l = MIN(l, FRAME_SIZE - ofs);
00579             bcopy(silence, myframe + ofs, l * 2);
00580             l_sampsent += l;
00581          } else {       /* silence is over, restart sound if loop */
00582             if (s->repeat == 0) {   /* last block */
00583                o->cursound = -1;
00584                o->nosound = 0;   /* allow audio data */
00585                if (ofs < FRAME_SIZE)   /* pad with silence */
00586                   bcopy(silence, myframe + ofs, (FRAME_SIZE - ofs) * 2);
00587             }
00588             l_sampsent = 0;
00589          }
00590       }
00591    }
00592    l = soundcard_writeframe(o, myframe);
00593    if (l > 0)
00594       o->sampsent = l_sampsent;  /* update status */
00595 }

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 674 of file chan_oss.c.

References ast_log(), ast_verbose(), DEFAULT_SAMPLE_RATE, chan_oss_pvt::device, chan_oss_pvt::duplex, ast_channel::fds, fmt, chan_oss_pvt::frags, chan_oss_pvt::lastopen, LOG_WARNING, O_CLOSE, option_verbose, chan_oss_pvt::owner, chan_oss_pvt::sounddev, VERBOSE_PREFIX_2, WARN_frag, WARN_speed, and chan_oss_pvt::warned.

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

00675 {
00676    int fmt, desired, res, fd;
00677 
00678    if (o->sounddev >= 0) {
00679       ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);
00680       close(o->sounddev);
00681       o->duplex = M_UNSET;
00682       o->sounddev = -1;
00683    }
00684    if (mode == O_CLOSE)    /* we are done */
00685       return 0;
00686    if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000)
00687       return -1;           /* don't open too often */
00688    o->lastopen = ast_tvnow();
00689    fd = o->sounddev = open(o->device, mode | O_NONBLOCK);
00690    if (fd < 0) {
00691       ast_log(LOG_WARNING, "Unable to re-open DSP device %s: %s\n", o->device, strerror(errno));
00692       return -1;
00693    }
00694    if (o->owner)
00695       o->owner->fds[0] = fd;
00696 
00697 #if __BYTE_ORDER == __LITTLE_ENDIAN
00698    fmt = AFMT_S16_LE;
00699 #else
00700    fmt = AFMT_S16_BE;
00701 #endif
00702    res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
00703    if (res < 0) {
00704       ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
00705       return -1;
00706    }
00707    switch (mode) {
00708    case O_RDWR:
00709       res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
00710       /* Check to see if duplex set (FreeBSD Bug) */
00711       res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);
00712       if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {
00713          if (option_verbose > 1)
00714             ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");
00715          o->duplex = M_FULL;
00716       };
00717       break;
00718 
00719    case O_WRONLY:
00720       o->duplex = M_WRITE;
00721       break;
00722 
00723    case O_RDONLY:
00724       o->duplex = M_READ;
00725       break;
00726    }
00727 
00728    fmt = 0;
00729    res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
00730    if (res < 0) {
00731       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00732       return -1;
00733    }
00734    fmt = desired = DEFAULT_SAMPLE_RATE;   /* 8000 Hz desired */
00735    res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
00736 
00737    if (res < 0) {
00738       ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
00739       return -1;
00740    }
00741    if (fmt != desired) {
00742       if (!(o->warned & WARN_speed)) {
00743          ast_log(LOG_WARNING,
00744              "Requested %d Hz, got %d Hz -- sound may be choppy\n",
00745              desired, fmt);
00746          o->warned |= WARN_speed;
00747       }
00748    }
00749    /*
00750     * on Freebsd, SETFRAGMENT does not work very well on some cards.
00751     * Default to use 256 bytes, let the user override
00752     */
00753    if (o->frags) {
00754       fmt = o->frags;
00755       res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
00756       if (res < 0) {
00757          if (!(o->warned & WARN_frag)) {
00758             ast_log(LOG_WARNING,
00759                "Unable to set fragment size -- sound may be choppy\n");
00760             o->warned |= WARN_frag;
00761          }
00762       }
00763    }
00764    /* on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */
00765    res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
00766    res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
00767    /* it may fail if we are in half duplex, never mind */
00768    return 0;
00769 }

static void* sound_thread void *  arg  )  [static]
 

Definition at line 597 of file chan_oss.c.

References ast_log(), ast_select(), chan_oss_pvt::cursound, DEFAULT_SAMPLE_RATE, FRAME_SIZE, sound::ind, LOG_WARNING, MAX, O_CLOSE, chan_oss_pvt::owner, setformat(), chan_oss_pvt::sndcmd, chan_oss_pvt::sounddev, and sounds.

00598 {
00599    char ign[4096];
00600    struct chan_oss_pvt *o = (struct chan_oss_pvt *) arg;
00601 
00602    /*
00603     * Just in case, kick the driver by trying to read from it.
00604     * Ignore errors - this read is almost guaranteed to fail.
00605     */
00606    read(o->sounddev, ign, sizeof(ign));
00607    for (;;) {
00608       fd_set rfds, wfds;
00609       int maxfd, res;
00610       struct timeval *to = NULL, t;
00611 
00612       FD_ZERO(&rfds);
00613       FD_ZERO(&wfds);
00614       FD_SET(o->sndcmd[0], &rfds);
00615       maxfd = o->sndcmd[0];   /* pipe from the main process */
00616       if (o->cursound > -1 && o->sounddev < 0)
00617          setformat(o, O_RDWR);   /* need the channel, try to reopen */
00618       else if (o->cursound == -1 && o->owner == NULL)
00619          setformat(o, O_CLOSE);  /* can close */
00620       if (o->sounddev > -1) {
00621          if (!o->owner) {  /* no one owns the audio, so we must drain it */
00622             FD_SET(o->sounddev, &rfds);
00623             maxfd = MAX(o->sounddev, maxfd);
00624          }
00625          if (o->cursound > -1) {
00626             /*
00627              * We would like to use select here, but the device
00628              * is always writable, so this would become busy wait.
00629              * So we rather set a timeout to 1/2 of the frame size.
00630              */
00631             t.tv_sec = 0;
00632             t.tv_usec = (1000000 * FRAME_SIZE) / (5 * DEFAULT_SAMPLE_RATE);
00633             to = &t;
00634          }
00635       }
00636       /* ast_select emulates linux behaviour in terms of timeout handling */
00637       res = ast_select(maxfd + 1, &rfds, &wfds, NULL, to);
00638       if (res < 0) {
00639          ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
00640          sleep(1);
00641          continue;
00642       }
00643       if (FD_ISSET(o->sndcmd[0], &rfds)) {
00644          /* read which sound to play from the pipe */
00645          int i, what = -1;
00646 
00647          read(o->sndcmd[0], &what, sizeof(what));
00648          for (i = 0; sounds[i].ind != -1; i++) {
00649             if (sounds[i].ind == what) {
00650                o->cursound = i;
00651                o->sampsent = 0;
00652                o->nosound = 1;   /* block audio from pbx */
00653                break;
00654             }
00655          }
00656          if (sounds[i].ind == -1)
00657             ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
00658       }
00659       if (o->sounddev > -1) {
00660          if (FD_ISSET(o->sounddev, &rfds))   /* read and ignore errors */
00661             read(o->sounddev, ign, sizeof(ign));
00662          if (to != NULL)         /* maybe it is possible to write */
00663             send_sound(o);
00664       }
00665    }
00666    return NULL;            /* Never reached */
00667 }

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

Write an exactly FRAME_SIZE sized frame

Definition at line 516 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().

00517 {
00518    int res;
00519 
00520    if (o->sounddev < 0)
00521       setformat(o, O_RDWR);
00522    if (o->sounddev < 0)
00523       return 0;            /* not fatal */
00524    /*
00525     * Nothing complex to manage the audio device queue.
00526     * If the buffer is full just drop the extra, otherwise write.
00527     * XXX in some cases it might be useful to write anyways after
00528     * a number of failures, to restart the output chain.
00529     */
00530    res = used_blocks(o);
00531    if (res > o->queuesize) {  /* no room to write a block */
00532       if (o->w_errors++ == 0 && (oss_debug & 0x4))
00533          ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);
00534       return 0;
00535    }
00536    o->w_errors = 0;
00537    return write(o->sounddev, (void *)data, FRAME_SIZE * 2);
00538 }

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

store the boost factor

Definition at line 1409 of file chan_oss.c.

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

Referenced by do_boost(), and store_config().

01410 {
01411    double boost = 0;
01412    if (sscanf(s, "%lf", &boost) != 1) {
01413       ast_log(LOG_WARNING, "invalid boost <%s>\n", s);
01414       return;
01415    }
01416    if (boost < -BOOST_MAX) {
01417       ast_log(LOG_WARNING, "boost %s too small, using %d\n", s, -BOOST_MAX);
01418       boost = -BOOST_MAX;
01419    } else if (boost > BOOST_MAX) {
01420       ast_log(LOG_WARNING, "boost %s too large, using %d\n", s, BOOST_MAX);
01421       boost = BOOST_MAX;
01422    }
01423    boost = exp(log(10) * boost / 20) * BOOST_SCALE;
01424    o->boost = boost;
01425    ast_log(LOG_WARNING, "setting boost %s to %d\n", s, o->boost);
01426 }

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

store the callerid components

Definition at line 1485 of file chan_oss.c.

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

Referenced by store_config().

01486 {
01487    ast_callerid_split(s, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
01488 }

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

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

Definition at line 1493 of file chan_oss.c.

References ast_calloc, ast_jb_read_conf(), ast_strdup, ast_variable_browse(), chan_oss_pvt::autoanswer, chan_oss_pvt::autohangup, chan_oss_pvt::ctx, chan_oss_pvt::device, chan_oss_pvt::ext, chan_oss_pvt::frags, global_jbconf, chan_oss_pvt::language, chan_oss_pvt::lastopen, M_BOOL, M_END, M_F, M_START, M_STR, M_UINT, chan_oss_pvt::mohinterpret, ast_variable::name, chan_oss_pvt::name, ast_variable::next, oss_default, chan_oss_pvt::overridecontext, chan_oss_pvt::queuesize, store_boost(), store_callerid(), store_mixer(), and ast_variable::value.

Referenced by load_module().

01494 {
01495    struct ast_variable *v;
01496    struct chan_oss_pvt *o;
01497 
01498    if (ctg == NULL) {
01499       o = &oss_default;
01500       ctg = "general";
01501    } else {
01502       if (!(o = ast_calloc(1, sizeof(*o))))
01503          return NULL;
01504       *o = oss_default;
01505       /* "general" is also the default thing */
01506       if (strcmp(ctg, "general") == 0) {
01507          o->name = ast_strdup("dsp");
01508          oss_active = o->name;
01509          goto openit;
01510       }
01511       o->name = ast_strdup(ctg);
01512    }
01513 
01514    strcpy(o->mohinterpret, "default");
01515 
01516    o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */
01517    /* fill other fields from configuration */
01518    for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
01519       M_START(v->name, v->value);
01520 
01521       /* handle jb conf */
01522       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
01523          continue;
01524 
01525       M_BOOL("autoanswer", o->autoanswer)
01526       M_BOOL("autohangup", o->autohangup)
01527       M_BOOL("overridecontext", o->overridecontext)
01528       M_STR("device", o->device)
01529       M_UINT("frags", o->frags)
01530       M_UINT("debug", oss_debug)
01531       M_UINT("queuesize", o->queuesize)
01532       M_STR("context", o->ctx)
01533       M_STR("language", o->language)
01534       M_STR("mohinterpret", o->mohinterpret)
01535       M_STR("extension", o->ext)
01536       M_F("mixer", store_mixer(o, v->value))
01537       M_F("callerid", store_callerid(o, v->value))
01538       M_F("boost", store_boost(o, v->value))
01539 
01540       M_END(/* */);
01541    }
01542    if (ast_strlen_zero(o->device))
01543       ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
01544    if (o->mixer_cmd) {
01545       char *cmd;
01546 
01547       asprintf(&cmd, "mixer %s", o->mixer_cmd);
01548       ast_log(LOG_WARNING, "running [%s]\n", cmd);
01549       system(cmd);
01550       free(cmd);
01551    }
01552    if (o == &oss_default)     /* we are done with the default */
01553       return NULL;
01554 
01555   openit:
01556 #if TRYOPEN
01557    if (setformat(o, O_RDWR) < 0) {  /* open device */
01558       if (option_verbose > 0) {
01559          ast_verbose(VERBOSE_PREFIX_2 "Device %s not detected\n", ctg);
01560          ast_verbose(VERBOSE_PREFIX_2 "Turn off OSS support by adding " "'noload=chan_oss.so' in /etc/asterisk/modules.conf\n");
01561       }
01562       goto error;
01563    }
01564    if (o->duplex != M_FULL)
01565       ast_log(LOG_WARNING, "XXX I don't work right with non " "full-duplex sound cards XXX\n");
01566 #endif /* TRYOPEN */
01567    if (pipe(o->sndcmd) != 0) {
01568       ast_log(LOG_ERROR, "Unable to create pipe\n");
01569       goto error;
01570    }
01571    ast_pthread_create_background(&o->sthread, NULL, sound_thread, o);
01572    /* link into list of devices */
01573    if (o != &oss_default) {
01574       o->next = oss_default.next;
01575       oss_default.next = o;
01576    }
01577    return o;
01578 
01579   error:
01580    if (o != &oss_default)
01581       free(o);
01582    return NULL;
01583 }

static void store_mixer struct chan_oss_pvt o,
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 1466 of file chan_oss.c.

References ast_log(), and LOG_WARNING.

Referenced by store_config().

01467 {
01468    int i;
01469 
01470    for (i = 0; i < strlen(s); i++) {
01471       if (!isalnum(s[i]) && index(" \t-/", s[i]) == NULL) {
01472          ast_log(LOG_WARNING, "Suspect char %c in mixer cmd, ignoring:\n\t%s\n", s[i], s);
01473          return;
01474       }
01475    }
01476    if (o->mixer_cmd)
01477       free(o->mixer_cmd);
01478    o->mixer_cmd = ast_strdup(s);
01479    ast_log(LOG_WARNING, "setting mixer %s\n", s);
01480 }

static int unload_module void   )  [static]
 

Definition at line 1623 of file chan_oss.c.

References ast_channel_unregister(), ast_cli_unregister_multiple(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_oss, chan_oss_pvt::next, oss_default, oss_tech, chan_oss_pvt::owner, chan_oss_pvt::sndcmd, and chan_oss_pvt::sounddev.

01624 {
01625    struct chan_oss_pvt *o;
01626 
01627    ast_channel_unregister(&oss_tech);
01628    ast_cli_unregister_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry));
01629 
01630    for (o = oss_default.next; o; o = o->next) {
01631       close(o->sounddev);
01632       if (o->sndcmd[0] > 0) {
01633          close(o->sndcmd[0]);
01634          close(o->sndcmd[1]);
01635       }
01636       if (o->owner)
01637          ast_softhangup(o->owner, AST_SOFTHANGUP_APPUNLOAD);
01638       if (o->owner)        /* XXX how ??? */
01639          return -1;
01640       /* XXX what about the thread ? */
01641       /* XXX what about the memory allocated ? */
01642    }
01643    return 0;
01644 }

static int used_blocks struct chan_oss_pvt o  )  [static]
 

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

Definition at line 494 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().

00495 {
00496    struct audio_buf_info info;
00497 
00498    if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {
00499       if (!(o->warned & WARN_used_blocks)) {
00500          ast_log(LOG_WARNING, "Error reading output space\n");
00501          o->warned |= WARN_used_blocks;
00502       }
00503       return 1;
00504    }
00505 
00506    if (o->total_blocks == 0) {
00507       if (0)               /* debugging */
00508          ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);
00509       o->total_blocks = info.fragments;
00510    }
00511 
00512    return o->total_blocks - info.fragments;
00513 }


Variable Documentation

const char active_usage[] [static]
 

Initial value:

   "Usage: console active [device]\n"
   "       If used without a parameter, displays which device is the current\n"
   "console.  If a device is specified, the console sound device is changed to\n"
   "the device specified.\n"

Definition at line 1400 of file chan_oss.c.

struct ast_cli_entry cli_oss[] [static]
 

Definition at line 1439 of file chan_oss.c.

Referenced by load_module(), and unload_module().

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

Definition at line 285 of file chan_oss.c.

struct ast_jb_conf default_jbconf [static]
 

Global jitterbuffer configuration - by default, jb is disabled

Definition at line 87 of file chan_oss.c.

struct ast_jb_conf global_jbconf [static]
 

Definition at line 94 of file chan_oss.c.

char* oss_active [static]
 

the active device

Definition at line 402 of file chan_oss.c.

int oss_debug [static]
 

Definition at line 287 of file chan_oss.c.

struct chan_oss_pvt oss_default [static]
 

Definition at line 387 of file chan_oss.c.

Referenced by console_active(), find_desc(), store_config(), and unload_module().

const struct ast_channel_tech oss_tech [static]
 

Definition at line 420 of file chan_oss.c.

Referenced by load_module(), oss_new(), oss_read(), and unload_module().

struct sound sounds[] [static]
 

Definition at line 304 of file chan_oss.c.

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

Definition at line 418 of file chan_oss.c.

const char transfer_usage[] [static]
 

Initial value:

   "Usage: console transfer <extension>[@context]\n"
   "       Transfers the currently connected call to the given extension (and\n"
   "context if specified)\n"

Definition at line 1373 of file chan_oss.c.


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen