00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <unistd.h>
00027 #include <netinet/in.h>
00028 #include <arpa/inet.h>
00029 #include <stdlib.h>
00030 #include <sys/time.h>
00031 #include <sys/times.h>
00032 #include <sys/types.h>
00033 #include <stdio.h>
00034 #include <errno.h>
00035 #include <string.h>
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7819 $")
00040
00041 #include "asterisk/lock.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/sched.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/endian.h"
00048 #include "asterisk/alaw.h"
00049
00050 #define BUF_SIZE 160
00051
00052
00053
00054 struct ast_filestream {
00055 void *reserved[AST_RESERVED_POINTERS];
00056
00057
00058
00059 FILE *f;
00060 struct ast_frame fr;
00061 char waste[AST_FRIENDLY_OFFSET];
00062 char empty;
00063 unsigned char buf[BUF_SIZE];
00064 #ifdef REALTIME_WRITE
00065 unsigned long start_time;
00066 #endif
00067 };
00068
00069
00070 AST_MUTEX_DEFINE_STATIC(pcm_lock);
00071 static int glistcnt = 0;
00072
00073 static char *name = "alaw";
00074 static char *desc = "Raw aLaw 8khz PCM Audio support";
00075 static char *exts = "alaw|al";
00076
00077 static char alaw_silence[BUF_SIZE];
00078
00079
00080 #if 0
00081
00082 static unsigned long get_time(void)
00083 {
00084 struct tms buf;
00085 clock_t cur;
00086
00087 cur = times( &buf );
00088 if( cur < 0 )
00089 {
00090 ast_log( LOG_WARNING, "Cannot get current time\n" );
00091 return 0;
00092 }
00093 return cur * 1000 / sysconf( _SC_CLK_TCK );
00094 }
00095 #endif
00096
00097 static struct ast_filestream *pcm_open(FILE *f)
00098 {
00099
00100
00101
00102 struct ast_filestream *tmp;
00103 if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00104 memset(tmp, 0, sizeof(struct ast_filestream));
00105 if (ast_mutex_lock(&pcm_lock)) {
00106 ast_log(LOG_WARNING, "Unable to lock pcm list\n");
00107 free(tmp);
00108 return NULL;
00109 }
00110 tmp->f = f;
00111 tmp->fr.data = tmp->buf;
00112 tmp->fr.frametype = AST_FRAME_VOICE;
00113 tmp->fr.subclass = AST_FORMAT_ALAW;
00114
00115 tmp->fr.src = name;
00116 tmp->fr.mallocd = 0;
00117 #ifdef REALTIME_WRITE
00118 tmp->start_time = get_time();
00119 #endif
00120 glistcnt++;
00121 ast_mutex_unlock(&pcm_lock);
00122 ast_update_use_count();
00123 }
00124 return tmp;
00125 }
00126
00127 static struct ast_filestream *pcm_rewrite(FILE *f, const char *comment)
00128 {
00129
00130
00131
00132 struct ast_filestream *tmp;
00133 if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00134 memset(tmp, 0, sizeof(struct ast_filestream));
00135 if (ast_mutex_lock(&pcm_lock)) {
00136 ast_log(LOG_WARNING, "Unable to lock pcm list\n");
00137 free(tmp);
00138 return NULL;
00139 }
00140 tmp->f = f;
00141 #ifdef REALTIME_WRITE
00142 tmp->start_time = get_time();
00143 #endif
00144 glistcnt++;
00145 ast_mutex_unlock(&pcm_lock);
00146 ast_update_use_count();
00147 } else
00148 ast_log(LOG_WARNING, "Out of memory\n");
00149 return tmp;
00150 }
00151
00152 static void pcm_close(struct ast_filestream *s)
00153 {
00154 if (ast_mutex_lock(&pcm_lock)) {
00155 ast_log(LOG_WARNING, "Unable to lock pcm list\n");
00156 return;
00157 }
00158 glistcnt--;
00159 ast_mutex_unlock(&pcm_lock);
00160 ast_update_use_count();
00161 fclose(s->f);
00162 free(s);
00163 s = NULL;
00164 }
00165
00166 static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
00167 {
00168 int res;
00169
00170
00171 s->fr.frametype = AST_FRAME_VOICE;
00172 s->fr.subclass = AST_FORMAT_ALAW;
00173 s->fr.offset = AST_FRIENDLY_OFFSET;
00174 s->fr.mallocd = 0;
00175 s->fr.data = s->buf;
00176 if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) {
00177 if (res)
00178 ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00179 return NULL;
00180 }
00181 s->fr.samples = res;
00182 s->fr.datalen = res;
00183 *whennext = s->fr.samples;
00184 return &s->fr;
00185 }
00186
00187 static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
00188 {
00189 int res;
00190 #ifdef REALTIME_WRITE
00191 unsigned long cur_time;
00192 unsigned long fpos;
00193 struct stat stat_buf;
00194 #endif
00195
00196 if (f->frametype != AST_FRAME_VOICE) {
00197 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00198 return -1;
00199 }
00200 if (f->subclass != AST_FORMAT_ALAW) {
00201 ast_log(LOG_WARNING, "Asked to write non-alaw frame (%d)!\n", f->subclass);
00202 return -1;
00203 }
00204
00205 #ifdef REALTIME_WRITE
00206 cur_time = get_time();
00207 fpos = ( cur_time - fs->start_time ) * 8;
00208
00209
00210
00211
00212 fstat(fileno(fs->f), &stat_buf );
00213 if (stat_buf.st_size > fpos ) {
00214 fpos += f->datalen;
00215 }
00216
00217 if (stat_buf.st_size < fpos) {
00218
00219 char buf[ 512 ];
00220 unsigned long cur, to_write;
00221
00222 cur = stat_buf.st_size;
00223 if (fseek(fs->f, cur, SEEK_SET) < 0) {
00224 ast_log( LOG_WARNING, "Cannot seek in file: %s\n", strerror(errno) );
00225 return -1;
00226 }
00227 memset(buf, 0x55, 512);
00228 while (cur < fpos) {
00229 to_write = fpos - cur;
00230 if (to_write > 512) {
00231 to_write = 512;
00232 }
00233 fwrite(buf, 1, to_write, fs->f);
00234 cur += to_write;
00235 }
00236 }
00237
00238
00239 if (fseek(s->f, fpos, SEEK_SET) < 0) {
00240 ast_log( LOG_WARNING, "Cannot seek in file: %s\n", strerror(errno) );
00241 return -1;
00242 }
00243 #endif
00244
00245 if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
00246 ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
00247 return -1;
00248 }
00249 return 0;
00250 }
00251
00252 static int pcm_seek(struct ast_filestream *fs, long sample_offset, int whence)
00253 {
00254 long cur, max, offset = 0;
00255
00256 cur = ftell(fs->f);
00257 fseek(fs->f, 0, SEEK_END);
00258 max = ftell(fs->f);
00259
00260 switch (whence) {
00261 case SEEK_SET:
00262 offset = sample_offset;
00263 break;
00264 case SEEK_END:
00265 offset = max - sample_offset;
00266 break;
00267 case SEEK_CUR:
00268 case SEEK_FORCECUR:
00269 offset = cur + sample_offset;
00270 break;
00271 }
00272
00273 switch (whence) {
00274 case SEEK_FORCECUR:
00275 if (offset > max) {
00276 size_t left = offset - max;
00277 size_t res;
00278
00279 while (left) {
00280 res = fwrite(alaw_silence, sizeof(alaw_silence[0]),
00281 (left > BUF_SIZE) ? BUF_SIZE : left, fs->f);
00282 if (res == -1)
00283 return res;
00284 left -= res * sizeof(alaw_silence[0]);
00285 }
00286 return offset;
00287 }
00288
00289 default:
00290 offset = (offset > max) ? max : offset;
00291 offset = (offset < 0) ? 0 : offset;
00292 return fseek(fs->f, offset, SEEK_SET);
00293 }
00294 }
00295
00296 static int pcm_trunc(struct ast_filestream *fs)
00297 {
00298 return ftruncate(fileno(fs->f), ftell(fs->f));
00299 }
00300
00301 static long pcm_tell(struct ast_filestream *fs)
00302 {
00303 off_t offset;
00304 offset = ftell(fs->f);
00305 return offset;
00306 }
00307
00308
00309 static char *pcm_getcomment(struct ast_filestream *s)
00310 {
00311 return NULL;
00312 }
00313
00314 int load_module()
00315 {
00316 int index;
00317
00318 for (index = 0; index < (sizeof(alaw_silence) / sizeof(alaw_silence[0])); index++)
00319 alaw_silence[index] = AST_LIN2A(0);
00320
00321 return ast_format_register(name, exts, AST_FORMAT_ALAW,
00322 pcm_open,
00323 pcm_rewrite,
00324 pcm_write,
00325 pcm_seek,
00326 pcm_trunc,
00327 pcm_tell,
00328 pcm_read,
00329 pcm_close,
00330 pcm_getcomment);
00331 }
00332
00333 int unload_module()
00334 {
00335 return ast_format_unregister(name);
00336 }
00337
00338 int usecount()
00339 {
00340 return glistcnt;
00341 }
00342
00343 char *description()
00344 {
00345 return desc;
00346 }
00347
00348
00349 char *key()
00350 {
00351 return ASTERISK_GPL_KEY;
00352 }