📄 chan_oss.c
字号:
/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 1999 - 2005, Digium, Inc. * * Mark Spencer <markster@digium.com> * * FreeBSD changes and multiple device support by Luigi Rizzo, 2005.05.25 * note-this code best seen with ts=8 (8-spaces tabs) in the editor * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. *//*! \file * * \brief Channel driver for OSS sound cards * * \author Mark Spencer <markster@digium.com> * \author Luigi Rizzo * * \par See also * \arg \ref Config_oss * * \ingroup channel_drivers *//*** MODULEINFO <depend>ossaudio</depend> ***/#include "asterisk.h"ASTERISK_FILE_VERSION(__FILE__, "$Revision: 108796 $")#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>#ifdef __linux#include <linux/soundcard.h>#elif defined(__FreeBSD__)#include <sys/soundcard.h>#else#include <soundcard.h>#endif#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"/* ringtones we use */#include "busy.h"#include "ringtone.h"#include "ring10.h"#include "answer.h"/*! Global jitterbuffer configuration - by default, jb is disabled */static struct ast_jb_conf default_jbconf ={ .flags = 0, .max_size = -1, .resync_threshold = -1, .impl = "",};static struct ast_jb_conf global_jbconf;/* * Basic mode of operation: * * we have one keyboard (which receives commands from the keyboard) * and multiple headset's connected to audio cards. * Cards/Headsets are named as the sections of oss.conf. * The section called [general] contains the default parameters. * * At any time, the keyboard is attached to one card, and you * can switch among them using the command 'console foo' * where 'foo' is the name of the card you want. * * oss.conf parameters areSTART_CONFIG[general] ; General config options, with default values shown. ; You should use one section per device, with [general] being used ; for the first device and also as a template for other devices. ; ; All but 'debug' can go also in the device-specific sections. ; ; debug = 0x0 ; misc debug flags, default is 0 ; Set the device to use for I/O ; device = /dev/dsp ; Optional mixer command to run upon startup (e.g. to set ; volume levels, mutes, etc. ; mixer = ; Software mic volume booster (or attenuator), useful for sound ; cards or microphones with poor sensitivity. The volume level ; is in dB, ranging from -20.0 to +20.0 ; boost = n ; mic volume boost in dB ; Set the callerid for outgoing calls ; callerid = John Doe <555-1234> ; autoanswer = no ; no autoanswer on call ; autohangup = yes ; hangup when other party closes ; extension = s ; default extension to call ; context = default ; default context for outgoing calls ; language = "" ; default language ; Default Music on Hold class to use when this channel is placed on hold in ; the case that the music class is not set on the channel with ; Set(CHANNEL(musicclass)=whatever) in the dialplan and the peer channel ; putting this one on hold did not suggest a class to use. ; ; mohinterpret=default ; If you set overridecontext to 'yes', then the whole dial string ; will be interpreted as an extension, which is extremely useful ; to dial SIP, IAX and other extensions which use the '@' character. ; The default is 'no' just for backward compatibility, but the ; suggestion is to change it. ; overridecontext = no ; if 'no', the last @ will start the context ; if 'yes' the whole string is an extension. ; low level device parameters in case you have problems with the ; device driver on your operating system. You should not touch these ; unless you know what you are doing. ; queuesize = 10 ; frames in device driver ; frags = 8 ; argument to SETFRAGMENT ;------------------------------ JITTER BUFFER CONFIGURATION -------------------------- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of an ; OSS channel. Defaults to "no". An enabled jitterbuffer will ; be used only if the sending side can create and the receiving ; side can not accept jitter. The OSS channel can't accept jitter, ; thus an enabled jitterbuffer on the receive OSS side will always ; be used if the sending side can create jitter. ; jbmaxsize = 200 ; Max length of the jitterbuffer in milliseconds. ; jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is ; resynchronized. Useful to improve the quality of the voice, with ; big jumps in/broken timestamps, usualy sent from exotic devices ; and programs. Defaults to 1000. ; jbimpl = fixed ; Jitterbuffer implementation, used on the receiving side of an OSS ; channel. Two implementations are currenlty available - "fixed" ; (with size always equals to jbmax-size) and "adaptive" (with ; variable size, actually the new jb of IAX2). Defaults to fixed. ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no". ;-----------------------------------------------------------------------------------[card1] ; device = /dev/dsp1 ; alternate deviceEND_CONFIG.. and so on for the other cards. *//* * Helper macros to parse config arguments. They will go in a common * header file if their usage is globally accepted. In the meantime, * we define them here. Typical usage is as below. * Remember to open a block right before M_START (as it declares * some variables) and use the M_* macros WITHOUT A SEMICOLON: * * { * M_START(v->name, v->value) * * M_BOOL("dothis", x->flag1) * M_STR("name", x->somestring) * M_F("bar", some_c_code) * M_END(some_final_statement) * ... other code in the block * } * * XXX NOTE these macros should NOT be replicated in other parts of asterisk. * Likely we will come up with a better way of doing config file parsing. */#define M_START(var, val) \ char *__s = var; char *__val = val;#define M_END(x) x;#define M_F(tag, f) if (!strcasecmp((__s), tag)) { f; } else#define M_BOOL(tag, dst) M_F(tag, (dst) = ast_true(__val) )#define M_UINT(tag, dst) M_F(tag, (dst) = strtoul(__val, NULL, 0) )#define M_STR(tag, dst) M_F(tag, ast_copy_string(dst, __val, sizeof(dst)))/* * The following parameters are used in the driver: * * FRAME_SIZE the size of an audio frame, in samples. * 160 is used almost universally, so you should not change it. * * FRAGS the argument for the SETFRAGMENT ioctl. * Overridden by the 'frags' parameter in oss.conf * * Bits 0-7 are the base-2 log of the device's block size, * bits 16-31 are the number of blocks in the driver's queue. * There are a lot of differences in the way this parameter * is supported by different drivers, so you may need to * experiment a bit with the value. * A good default for linux is 30 blocks of 64 bytes, which * results in 6 frames of 320 bytes (160 samples). * FreeBSD works decently with blocks of 256 or 512 bytes, * leaving the number unspecified. * Note that this only refers to the device buffer size, * this module will then try to keep the lenght of audio * buffered within small constraints. * * QUEUE_SIZE The max number of blocks actually allowed in the device * driver's buffer, irrespective of the available number. * Overridden by the 'queuesize' parameter in oss.conf * * Should be >=2, and at most as large as the hw queue above * (otherwise it will never be full). */#define FRAME_SIZE 160#define QUEUE_SIZE 10#if defined(__FreeBSD__)#define FRAGS 0x8#else#define FRAGS ( ( (6 * 5) << 16 ) | 0x6 )#endif/* * XXX text message sizes are probably 256 chars, but i am * not sure if there is a suitable definition anywhere. */#define TEXT_SIZE 256#if 0#define TRYOPEN 1 /* try to open on startup */#endif#define O_CLOSE 0x444 /* special 'close' mode for device *//* Which device to use */#if defined( __OpenBSD__ ) || defined( __NetBSD__ )#define DEV_DSP "/dev/audio"#else#define DEV_DSP "/dev/dsp"#endif#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endif#ifndef MAX#define MAX(a,b) ((a) > (b) ? (a) : (b))#endifstatic char *config = "oss.conf"; /* default config file */static int oss_debug;/* * Each sound is made of 'datalen' samples of sound, repeated as needed to * generate 'samplen' samples of data, then followed by 'silencelen' samples * of silence. The loop is repeated if 'repeat' is set. */struct sound { int ind; char *desc; short *data; int datalen; int samplen; int silencelen; int repeat;};static struct sound sounds[] = { { AST_CONTROL_RINGING, "RINGING", ringtone, sizeof(ringtone)/2, 16000, 32000, 1 }, { AST_CONTROL_BUSY, "BUSY", busy, sizeof(busy)/2, 4000, 4000, 1 }, { AST_CONTROL_CONGESTION, "CONGESTION", busy, sizeof(busy)/2, 2000, 2000, 1 }, { AST_CONTROL_RING, "RING10", ring10, sizeof(ring10)/2, 16000, 32000, 1 }, { AST_CONTROL_ANSWER, "ANSWER", answer, sizeof(answer)/2, 2200, 0, 0 }, { -1, NULL, 0, 0, 0, 0 }, /* end marker */};/* * descriptor for one of our channels. * There is one used for 'default' values (from the [general] entry in * the configuration file), and then one instance for each device * (the default is cloned from [general], others are only created * if the relevant section exists). */struct chan_oss_pvt { struct chan_oss_pvt *next; char *name; /* * cursound indicates which in struct sound we play. -1 means nothing, * any other value is a valid sound, in which case sampsent indicates * the next sample to send in [0..samplen + silencelen] * nosound is set to disable the audio data from the channel * (so we can play the tones etc.). */ int sndcmd[2]; /* Sound command pipe */ int cursound; /* index of sound to send */ int sampsent; /* # of sound samples sent */ int nosound; /* set to block audio from the PBX */ int total_blocks; /* total blocks in the output device */ int sounddev; enum { M_UNSET, M_FULL, M_READ, M_WRITE } duplex; int autoanswer; int autohangup; int hookstate; char *mixer_cmd; /* initial command to issue to the mixer */ unsigned int queuesize; /* max fragments in queue */ unsigned int frags; /* parameter for SETFRAGMENT */ int warned; /* various flags used for warnings */#define WARN_used_blocks 1#define WARN_speed 2#define WARN_frag 4 int w_errors; /* overfull in the write path */ struct timeval lastopen; int overridecontext; int mute; /* boost support. BOOST_SCALE * 10 ^(BOOST_MAX/20) must * be representable in 16 bits to avoid overflows. */#define BOOST_SCALE (1<<9)#define BOOST_MAX 40 /* slightly less than 7 bits */ int boost; /* input boost, scaled by BOOST_SCALE */ char device[64]; /* device to open */ pthread_t sthread; struct ast_channel *owner; char ext[AST_MAX_EXTENSION]; char ctx[AST_MAX_CONTEXT]; char language[MAX_LANGUAGE]; char cid_name[256]; /*XXX */ char cid_num[256]; /*XXX */ char mohinterpret[MAX_MUSICCLASS]; /* buffers used in oss_write */ char oss_write_buf[FRAME_SIZE * 2]; int oss_write_dst; /* buffers used in oss_read - AST_FRIENDLY_OFFSET space for headers * plus enough room for a full frame */ char oss_read_buf[FRAME_SIZE * 2 + AST_FRIENDLY_OFFSET]; int readpos; /* read position above */ struct ast_frame read_f; /* returned by oss_read */};static struct chan_oss_pvt oss_default = { .cursound = -1, .sounddev = -1, .duplex = M_UNSET, /* XXX check this */ .autoanswer = 1, .autohangup = 1, .queuesize = QUEUE_SIZE, .frags = FRAGS, .ext = "s", .ctx = "default", .readpos = AST_FRIENDLY_OFFSET, /* start here on reads */ .lastopen = { 0, 0 }, .boost = BOOST_SCALE,};static char *oss_active; /* the active device */static int setformat(struct chan_oss_pvt *o, int mode);static struct ast_channel *oss_request(const char *type, int format, void *data, int *cause);static int oss_digit_begin(struct ast_channel *c, char digit);static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration);static int oss_text(struct ast_channel *c, const char *text);static int oss_hangup(struct ast_channel *c);static int oss_answer(struct ast_channel *c);static struct ast_frame *oss_read(struct ast_channel *chan);static int oss_call(struct ast_channel *c, char *dest, int timeout);static int oss_write(struct ast_channel *chan, struct ast_frame *f);static int oss_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);static char tdesc[] = "OSS Console Channel Driver";static const struct ast_channel_tech oss_tech = { .type = "Console", .description = tdesc, .capabilities = AST_FORMAT_SLINEAR, .requester = oss_request, .send_digit_begin = oss_digit_begin, .send_digit_end = oss_digit_end, .send_text = oss_text, .hangup = oss_hangup, .answer = oss_answer, .read = oss_read, .call = oss_call, .write = oss_write, .indicate = oss_indicate, .fixup = oss_fixup,};/* * returns a pointer to the descriptor with the given name */static struct chan_oss_pvt *find_desc(char *dev){ struct chan_oss_pvt *o = NULL; if (!dev) ast_log(LOG_WARNING, "null dev\n"); for (o = oss_default.next; o && o->name && dev && strcmp(o->name, dev) != 0; o = o->next); if (!o) ast_log(LOG_WARNING, "could not find <%s>\n", dev ? dev : "--no-device--"); return o;}/* * split a string in extension-context, returns pointers to malloc'ed * strings. * If we do not have 'overridecontext' then the last @ is considered as * a context separator, and the context is overridden. * This is usually not very necessary as you can play with the dialplan, * and it is nice not to need it because you have '@' in SIP addresses. * Return value is the buffer address. */static char *ast_ext_ctx(const char *src, char **ext, char **ctx){ struct chan_oss_pvt *o = find_desc(oss_active); if (ext == NULL || ctx == NULL) return NULL; /* error */ *ext = *ctx = NULL; if (src && *src != '\0') *ext = ast_strdup(src);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -