2
* Asterisk -- A telephony toolkit for Linux.
4
* Flat, binary, ulaw PCM file format.
6
* Copyright (C) 1999, Mark Spencer
8
* Mark Spencer <markster@linux-support.net>
10
* This program is free software, distributed under the terms of
11
* the GNU General Public License
14
#include <asterisk/channel.h>
15
#include <asterisk/file.h>
16
#include <asterisk/logger.h>
17
#include <asterisk/sched.h>
18
#include <asterisk/module.h>
19
#include <arpa/inet.h>
29
#define BUF_SIZE 160 /* 160 samples */
31
struct ast_filestream {
32
void *reserved[AST_RESERVED_POINTERS];
33
/* Believe it or not, we must decode/recode to account for the
35
/* This is what a filestream means to us */
36
int fd; /* Descriptor */
37
struct ast_channel *owner;
38
struct ast_frame fr; /* Frame information */
39
char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
40
char empty; /* Empty character */
41
unsigned char buf[BUF_SIZE]; /* Output Buffer */
45
struct ast_filestream *next;
49
static struct ast_filestream *glist = NULL;
50
static pthread_mutex_t pcm_lock = PTHREAD_MUTEX_INITIALIZER;
51
static int glistcnt = 0;
53
static char *name = "pcm";
54
static char *desc = "Raw uLaw 8khz Audio support (PCM)";
55
static char *exts = "pcm|ulaw|ul|mu";
57
static struct ast_filestream *pcm_open(int fd)
59
/* We don't have any header to read or anything really, but
60
if we did, it would go here. We also might want to check
61
and be sure it's a valid file. */
62
struct ast_filestream *tmp;
63
if ((tmp = malloc(sizeof(struct ast_filestream)))) {
64
memset(tmp, 0, sizeof(struct ast_filestream));
65
if (pthread_mutex_lock(&pcm_lock)) {
66
ast_log(LOG_WARNING, "Unable to lock pcm list\n");
74
tmp->fr.data = tmp->buf;
75
tmp->fr.frametype = AST_FRAME_VOICE;
76
tmp->fr.subclass = AST_FORMAT_ULAW;
77
/* datalen will vary for each frame */
80
tmp->lasttimeout = -1;
82
pthread_mutex_unlock(&pcm_lock);
83
ast_update_use_count();
88
static struct ast_filestream *pcm_rewrite(int fd, char *comment)
90
/* We don't have any header to read or anything really, but
91
if we did, it would go here. We also might want to check
92
and be sure it's a valid file. */
93
struct ast_filestream *tmp;
94
if ((tmp = malloc(sizeof(struct ast_filestream)))) {
95
memset(tmp, 0, sizeof(struct ast_filestream));
96
if (pthread_mutex_lock(&pcm_lock)) {
97
ast_log(LOG_WARNING, "Unable to lock pcm list\n");
105
tmp->lasttimeout = -1;
107
pthread_mutex_unlock(&pcm_lock);
108
ast_update_use_count();
110
ast_log(LOG_WARNING, "Out of memory\n");
114
static struct ast_frame *pcm_read(struct ast_filestream *s)
119
static void pcm_close(struct ast_filestream *s)
121
struct ast_filestream *tmp, *tmpl = NULL;
122
if (pthread_mutex_lock(&pcm_lock)) {
123
ast_log(LOG_WARNING, "Unable to lock pcm list\n");
130
tmpl->next = tmp->next;
140
s->owner->stream = NULL;
141
if (s->owner->streamid > -1)
142
ast_sched_del(s->owner->sched, s->owner->streamid);
143
s->owner->streamid = -1;
145
pthread_mutex_unlock(&pcm_lock);
146
ast_update_use_count();
148
ast_log(LOG_WARNING, "Freeing a filestream we don't seem to own\n");
153
static int ast_read_callback(void *data)
158
struct ast_filestream *s = data;
160
/* Send a frame from the file to the appropriate channel */
162
s->fr.frametype = AST_FRAME_VOICE;
163
s->fr.subclass = AST_FORMAT_ULAW;
164
s->fr.offset = AST_FRIENDLY_OFFSET;
167
if ((res = read(s->fd, s->buf, BUF_SIZE)) < 1) {
169
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
170
s->owner->streamid = -1;
173
s->fr.timelen = res / 8;
175
delay = s->fr.timelen;
176
/* Lastly, process the frame */
177
if (ast_write(s->owner, &s->fr)) {
178
ast_log(LOG_WARNING, "Failed to write frame\n");
179
s->owner->streamid = -1;
182
if (s->last.tv_usec || s->last.tv_usec) {
184
gettimeofday(&tv, NULL);
185
ms = 1000 * (tv.tv_sec - s->last.tv_sec) +
186
(tv.tv_usec - s->last.tv_usec) / 1000;
187
s->last.tv_sec = tv.tv_sec;
188
s->last.tv_usec = tv.tv_usec;
189
if ((ms - delay) * (ms - delay) > 4) {
190
/* Compensate if we're more than 2 ms off */
191
s->adj -= (ms - delay);
194
fprintf(stdout, "Delay is %d, adjustment is %d, last was %d\n", delay, s->adj, ms);
200
gettimeofday(&s->last, NULL);
201
if (s->lasttimeout != delay) {
202
/* We'll install the next timeout now. */
203
s->owner->streamid = ast_sched_add(s->owner->sched,
204
delay, ast_read_callback, s);
205
s->lasttimeout = delay;
207
/* Just come back again at the same time */
213
static int pcm_apply(struct ast_channel *c, struct ast_filestream *s)
215
/* Select our owner for this stream, and get the ball rolling. */
217
ast_read_callback(s);
221
static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
224
if (f->frametype != AST_FRAME_VOICE) {
225
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
228
if (f->subclass != AST_FORMAT_ULAW) {
229
ast_log(LOG_WARNING, "Asked to write non-ulaw frame (%d)!\n", f->subclass);
232
if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
233
ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
239
static char *pcm_getcomment(struct ast_filestream *s)
246
return ast_format_register(name, exts, AST_FORMAT_ULAW,
260
struct ast_filestream *tmp, *tmpl;
261
if (pthread_mutex_lock(&pcm_lock)) {
262
ast_log(LOG_WARNING, "Unable to lock pcm list\n");
268
ast_softhangup(tmp->owner);
273
pthread_mutex_unlock(&pcm_lock);
274
return ast_format_unregister(name);
280
if (pthread_mutex_lock(&pcm_lock)) {
281
ast_log(LOG_WARNING, "Unable to lock pcm list\n");
285
pthread_mutex_unlock(&pcm_lock);
297
return ASTERISK_GPL_KEY;