dect
/
asterisk
Archived
13
0
Fork 0

Version 0.1.0 from FTP

git-svn-id: http://svn.digium.com/svn/asterisk/trunk@65 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
markster 1999-11-21 02:26:43 +00:00
parent b3f95b5b13
commit 4c63f091a4
5 changed files with 618 additions and 0 deletions

268
formats/format_mp3.c Executable file
View File

@ -0,0 +1,268 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Everybody's favorite format: MP3 Files! Yay!
*
* Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/channel.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/sched.h>
#include <asterisk/module.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include "../channels/adtranvofr.h"
#define MP3_MAX_SIZE 1400
struct ast_filestream {
/* First entry MUST be reserved for the channel type */
void *reserved[AST_RESERVED_POINTERS];
/* This is what a filestream means to us */
int fd; /* Descriptor */
struct ast_channel *owner;
struct ast_filestream *next;
struct ast_frame *fr; /* Frame representation of buf */
char buf[sizeof(struct ast_frame) + MP3_MAX_SIZE + AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
int pos;
};
static struct ast_filestream *glist = NULL;
static pthread_mutex_t mp3_lock = PTHREAD_MUTEX_INITIALIZER;
static int glistcnt = 0;
static char *name = "mp3";
static char *desc = "MPEG-2 Layer 3 File Format Support";
static char *exts = "mp3|mpeg3";
#if 0
#define MP3_FRAMELEN 417
#else
#define MP3_FRAMELEN 400
#endif
#define MP3_OUTPUTLEN 2304 /* Bytes */
#define MP3_TIMELEN ((MP3_OUTPUTLEN * 1000 / 16000) )
static struct ast_filestream *mp3_open(int fd)
{
/* We don't have any header to read or anything really, but
if we did, it would go here. We also might want to check
and be sure it's a valid file. */
struct ast_filestream *tmp;
if ((tmp = malloc(sizeof(struct ast_filestream)))) {
if (pthread_mutex_lock(&mp3_lock)) {
ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
free(tmp);
return NULL;
}
tmp->next = glist;
glist = tmp;
tmp->fd = fd;
tmp->owner = NULL;
tmp->fr = (struct ast_frame *)tmp->buf;
tmp->fr->data = tmp->buf + sizeof(struct ast_frame);
tmp->fr->frametype = AST_FRAME_VOICE;
tmp->fr->subclass = AST_FORMAT_MP3;
/* datalen will vary for each frame */
tmp->fr->src = name;
tmp->fr->mallocd = 0;
glistcnt++;
pthread_mutex_unlock(&mp3_lock);
ast_update_use_count();
}
return tmp;
}
static struct ast_filestream *mp3_rewrite(int fd, char *comment)
{
/* We don't have any header to read or anything really, but
if we did, it would go here. We also might want to check
and be sure it's a valid file. */
struct ast_filestream *tmp;
if ((tmp = malloc(sizeof(struct ast_filestream)))) {
if (pthread_mutex_lock(&mp3_lock)) {
ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
free(tmp);
return NULL;
}
tmp->next = glist;
glist = tmp;
tmp->fd = fd;
tmp->owner = NULL;
tmp->fr = NULL;
glistcnt++;
pthread_mutex_unlock(&mp3_lock);
ast_update_use_count();
} else
ast_log(LOG_WARNING, "Out of memory\n");
return tmp;
}
static struct ast_frame *mp3_read(struct ast_filestream *s)
{
return NULL;
}
static void mp3_close(struct ast_filestream *s)
{
struct ast_filestream *tmp, *tmpl = NULL;
if (pthread_mutex_lock(&mp3_lock)) {
ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
return;
}
tmp = glist;
while(tmp) {
if (tmp == s) {
if (tmpl)
tmpl->next = tmp->next;
else
glist = tmp->next;
break;
}
tmpl = tmp;
tmp = tmp->next;
}
glistcnt--;
if (s->owner) {
s->owner->stream = NULL;
if (s->owner->streamid > -1)
ast_sched_del(s->owner->sched, s->owner->streamid);
s->owner->streamid = -1;
}
pthread_mutex_unlock(&mp3_lock);
ast_update_use_count();
if (!tmp)
ast_log(LOG_WARNING, "Freeing a filestream we don't seem to own\n");
close(s->fd);
free(s);
}
static int ast_read_callback(void *data)
{
/* XXX Don't assume frames are this size XXX */
u_int16_t size=MP3_FRAMELEN;
u_int32_t delay = -1;
int res;
struct ast_filestream *s = data;
/* Send a frame from the file to the appropriate channel */
/* Read the data into the buffer */
s->fr->offset = AST_FRIENDLY_OFFSET;
s->fr->datalen = size;
s->fr->data = s->buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
if ((res = read(s->fd, s->fr->data , size)) != size) {
ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno));
s->owner->streamid = -1;
return 0;
}
delay = MP3_TIMELEN;
s->fr->timelen = delay;
/* Lastly, process the frame */
if (ast_write(s->owner, s->fr)) {
ast_log(LOG_WARNING, "Failed to write frame\n");
s->owner->streamid = -1;
return 0;
}
return -1;
}
static int mp3_apply(struct ast_channel *c, struct ast_filestream *s)
{
/* Select our owner for this stream, and get the ball rolling. */
s->owner = c;
s->owner->streamid = ast_sched_add(s->owner->sched, MP3_TIMELEN, ast_read_callback, s);
ast_read_callback(s);
return 0;
}
static int mp3_write(struct ast_filestream *fs, struct ast_frame *f)
{
int res;
if (fs->fr) {
ast_log(LOG_WARNING, "Asked to write on a read stream??\n");
return -1;
}
if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1;
}
if (f->subclass != AST_FORMAT_MP3) {
ast_log(LOG_WARNING, "Asked to write non-mp3 frame!\n");
return -1;
}
if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
ast_log(LOG_WARNING, "Unable to write frame: res=%d (%s)\n", res, strerror(errno));
return -1;
}
return 0;
}
char *mp3_getcomment(struct ast_filestream *s)
{
return NULL;
}
int load_module()
{
return ast_format_register(name, exts, AST_FORMAT_MP3,
mp3_open,
mp3_rewrite,
mp3_apply,
mp3_write,
mp3_read,
mp3_close,
mp3_getcomment);
}
int unload_module()
{
struct ast_filestream *tmp, *tmpl;
if (pthread_mutex_lock(&mp3_lock)) {
ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
return -1;
}
tmp = glist;
while(tmp) {
if (tmp->owner)
ast_softhangup(tmp->owner);
tmpl = tmp;
tmp = tmp->next;
free(tmpl);
}
pthread_mutex_unlock(&mp3_lock);
return ast_format_unregister(name);
}
int usecount()
{
int res;
if (pthread_mutex_lock(&mp3_lock)) {
ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
return -1;
}
res = glistcnt;
pthread_mutex_unlock(&mp3_lock);
return res;
}
char *description()
{
return desc;
}

89
frame.c Executable file
View File

@ -0,0 +1,89 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Frame manipulation routines
*
* Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/frame.h>
#include <asterisk/logger.h>
#include <stdlib.h>
#include <string.h>
/*
* Important: I should be made more efficient. Frame headers should
* most definitely be cached
*/
void ast_frfree(struct ast_frame *fr)
{
if (fr->mallocd & AST_MALLOCD_DATA) {
if (fr->data)
free(fr->data - fr->offset);
}
if (fr->mallocd & AST_MALLOCD_SRC) {
if (fr->src)
free(fr->src);
}
if (fr->mallocd & AST_MALLOCD_HDR) {
free(fr);
}
}
void ast_frchain(struct ast_frame_chain *fc)
{
struct ast_frame_chain *last;
while(fc) {
last = fc;
fc = fc->next;
if (last->fr)
ast_frfree(last->fr);
free(last);
}
}
struct ast_frame *ast_frisolate(struct ast_frame *fr)
{
struct ast_frame *out;
if (!(fr->mallocd & AST_MALLOCD_HDR)) {
/* Allocate a new header if needed */
out = malloc(sizeof(struct ast_frame));
if (!out) {
ast_log(LOG_WARNING, "Out of memory\n");
return NULL;
}
out->frametype = fr->frametype;
out->subclass = fr->subclass;
out->datalen = 0;
out->timelen = fr->timelen;
out->offset = 0;
out->src = NULL;
out->data = NULL;
} else {
out = fr;
}
if (!(fr->mallocd & AST_MALLOCD_SRC)) {
if (fr->src)
out->src = strdup(fr->src);
} else
out->src = fr->src;
if (!(fr->mallocd & AST_MALLOCD_DATA)) {
out->data = malloc(fr->datalen + fr->offset);
out->data += fr->offset;
out->offset = fr->offset;
out->datalen = fr->datalen;
memcpy(out->data, fr->data, fr->datalen);
if (!out->data) {
ast_log(LOG_WARNING, "Out of memory\n");
return NULL;
}
}
out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
return out;
}

84
include/asterisk/file.h Executable file
View File

@ -0,0 +1,84 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Generic File Format Support.
*
* Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#ifndef _ASTERISK_FILE_H
#define _ASTERISK_FILE_H
#include <asterisk/channel.h>
#include <asterisk/frame.h>
#include <fcntl.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* Convenient for waiting */
#define AST_DIGIT_ANY "0123456789#*"
/* Defined by individual formats. First item MUST be a
pointer for use by the stream manager */
struct ast_filestream;
/* Register a new file format capability */
int ast_format_register(char *name, char *exts, int format,
struct ast_filestream * (*open)(int fd),
struct ast_filestream * (*rewrite)(int fd, char *comment),
int (*apply)(struct ast_channel *, struct ast_filestream *),
int (*write)(struct ast_filestream *, struct ast_frame *),
struct ast_frame * (*read)(struct ast_filestream *),
void (*close)(struct ast_filestream *),
char * (*getcomment)(struct ast_filestream *));
int ast_format_unregister(char *name);
/* Start streaming a file */
int ast_streamfile(struct ast_channel *c, char *filename);
/* Stop playback of a stream */
int ast_stopstream(struct ast_channel *c);
/* See if a given file exists in a given format. If fmt is NULL, any format is accepted.*/
int ast_fileexists(char *filename, char *fmt);
/* Rename a given file in a given format, or if fmt is NULL, then do so for all */
int ast_filerename(char *oldname, char *newname, char *fmt);
/* Delete a given file in a given format, or if fmt is NULL, then do so for all */
int ast_filedelete(char *filename, char *fmt);
/* Wait for a stream to stop or for any one of a given digit to arrive, Returns
0 if the stream finishes, the character if it was interrupted, and -1 on error */
char ast_waitstream(struct ast_channel *c, char *breakon);
/* Create an outgoing file stream. oflags are flags for the open() command, and
if check is non-zero, then it will not write a file if there are any files that
start with that name and have an extension */
struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int oflags, int check, mode_t mode);
/* Send a frame to a filestream -- note: does NOT free the frame, call ast_frfree manually */
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f);
/* Close a playback or recording stream */
int ast_closestream(struct ast_filestream *f);
#define AST_RESERVED_POINTERS 4
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif

101
include/asterisk/frame.h Executable file
View File

@ -0,0 +1,101 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Asterisk internal frame definitions.
*
* Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#ifndef _ASTERISK_FRAME_H
#define _ASTERISK_FRAME_H
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* A frame of data read used to communicate between
between channels and applications */
struct ast_frame {
int frametype; /* Kind of frame */
int subclass; /* Subclass, frame dependent */
int datalen; /* Length of data */
int timelen; /* Amount of time associated with this frame */
int mallocd; /* Was the data malloc'd? i.e. should we
free it when we discard the frame? */
int offset; /* How far into "data" the data really starts */
char *src; /* Optional source of frame for debugging */
void *data; /* Pointer to actual data */
};
struct ast_frame_chain {
/* XXX Should ast_frame chain's be just prt of frames, i.e. should they just link? XXX */
struct ast_frame *fr;
struct ast_frame_chain *next;
};
#define AST_FRIENDLY_OFFSET 64 /* It's polite for a a new frame to
have at least this number of bytes
of offset before your real frame data
so that additional headers can be
added. */
#define AST_MALLOCD_HDR (1 << 0) /* Need the header be free'd? */
#define AST_MALLOCD_DATA (1 << 1) /* Need the data be free'd? */
#define AST_MALLOCD_SRC (1 << 2) /* Need the source be free'd? (haha!) */
/* Frame types */
#define AST_FRAME_DTMF 1 /* A DTMF digit, subclass is the digit */
#define AST_FRAME_VOICE 2 /* Voice data, subclass is AST_FORMAT_* */
#define AST_FRAME_VIDEO 3 /* Video frame, maybe?? :) */
#define AST_FRAME_CONTROL 4 /* A control frame, subclass is AST_CONTROL_* */
#define AST_FRAME_NULL 5 /* An empty, useless frame */
/* Data formats for capabilities and frames alike */
#define AST_FORMAT_G723_1 (1 << 0) /* G.723.1 compression */
#define AST_FORMAT_GSM (1 << 1) /* GSM compression */
#define AST_FORMAT_ULAW (1 << 2) /* Raw mu-law data (G.711) */
#define AST_FORMAT_ALAW (1 << 3) /* Raw A-law data (G.711) */
#define AST_FORMAT_MP3 (1 << 4) /* MPEG-2 layer 3 */
#define AST_FORMAT_ADPCM (1 << 5) /* ADPCM */
#define AST_FORMAT_SLINEAR (1 << 6) /* Raw 16-bit Signed Linear (8000 Hz) PCM */
#define AST_FORMAT_MAX_AUDIO (1 << 15) /* Maximum audio format */
#define AST_FORMAT_JPEG (1 << 16) /* JPEG Images */
#define AST_FORMAT_PNG (1 << 17) /* PNG Images */
#define AST_FORMAT_H261 (1 << 18) /* H.261 Video */
#define AST_FORMAT_H263 (1 << 19) /* H.263 Video */
/* Control frame types */
#define AST_CONTROL_HANGUP 1 /* Other end has hungup */
#define AST_CONTROL_RING 2 /* Local ring */
#define AST_CONTROL_RINGING 3 /* Remote end is ringing */
#define AST_CONTROL_ANSWER 4 /* Remote end has answered */
#define AST_CONTROL_BUSY 5 /* Remote end is busy */
#define AST_CONTROL_TAKEOFFHOOK 6 /* Make it go off hook */
#define AST_CONTROL_OFFHOOK 7 /* Line is off hook */
/* Request a frame be allocated. source is an optional source of the frame,
len is the requested length, or "0" if the caller will supply the buffer */
struct ast_frame *ast_fralloc(char *source, int len);
/* Free a frame, and the memory it used if applicable */
void ast_frfree(struct ast_frame *fr);
/* Take a frame, and if it's not been malloc'd, make a malloc'd copy
and if the data hasn't been malloced then make the
data malloc'd. If you need to store frames, say for queueing, then
you should call this function. */
struct ast_frame *ast_frisolate(struct ast_frame *fr);
void ast_frchain(struct ast_frame_chain *fc);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif

76
include/asterisk/translate.h Executable file
View File

@ -0,0 +1,76 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Translate via the use of pseudo channels
*
* Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#ifndef _ASTERISK_TRANSLATE_H
#define _ASTERISK_TRANSLATE_H
#define MAX_FORMAT 32
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include <asterisk/frame.h>
/* Declared by individual translators */
struct ast_translator_pvt;
struct ast_translator {
char name[80];
int srcfmt;
int dstfmt;
struct ast_translator_pvt *(*new)();
int (*framein)(struct ast_translator_pvt *pvt, struct ast_frame *in);
struct ast_frame * (*frameout)(struct ast_translator_pvt *pvt);
void (*destroy)(struct ast_translator_pvt *pvt);
/* For performance measurements */
/* Generate an example frame */
struct ast_frame * (*sample)(void);
/* Cost in milliseconds for encoding/decoding 1 second of sound */
int cost;
/* For linking, not to be modified by the translator */
struct ast_translator *next;
};
struct ast_trans_pvt;
/* Create a pseudo channel which translates from a real channel into our
desired format. When a translator is installed, you should not use the
sub channel until you have stopped the translator. For all other
actions, use the real channel. Generally, translators should be created
when needed and immediately destroyed when no longer needed. */
/* Directions */
#define AST_DIRECTION_OUT 1
#define AST_DIRECTION_IN 2
#define AST_DIRECTION_BOTH 3
extern struct ast_channel *ast_translator_create(struct ast_channel *real, int format, int direction);
extern void ast_translator_destroy(struct ast_channel *tran);
/* Register a Codec translator */
extern int ast_register_translator(struct ast_translator *t);
/* Unregister same */
extern int ast_unregister_translator(struct ast_translator *t);
/* Given a list of sources, and a designed destination format, which should
I choose? */
extern int ast_translator_best_choice(int dst, int srcs);
extern struct ast_trans_pvt *ast_translator_build_path(int source, int dest);
extern void ast_translator_free_path(struct ast_trans_pvt *tr);
extern struct ast_frame_chain *ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif