Some formats are able to handle short reads while others are not, so restore the previous behavior for the format modules so that we don't have spurious errors when playing back files. ASTERISK-27232 #close Reported by: Jens T. Change-Id: Iab7f52b25a394f277566c8a2a4b15a692280a300
160 lines
4.4 KiB
C
160 lines
4.4 KiB
C
/*
|
|
* Asterisk -- An open source telephony toolkit.
|
|
*
|
|
* Copyright (C) 1999 - 2008, Anthony Minessale and Digium, Inc.
|
|
* Anthony Minessale (anthmct@yahoo.com)
|
|
* Kevin P. Fleming <kpfleming@digium.com>
|
|
*
|
|
* 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 ITU G.722.1 Annex C (Siren14, licensed from Polycom) format, 48kbps bitrate only
|
|
* \arg File name extensions: siren14
|
|
* \ingroup formats
|
|
*/
|
|
|
|
/*** MODULEINFO
|
|
<support_level>core</support_level>
|
|
***/
|
|
|
|
#include "asterisk.h"
|
|
|
|
#include "asterisk/mod_format.h"
|
|
#include "asterisk/module.h"
|
|
#include "asterisk/endian.h"
|
|
#include "asterisk/format_cache.h"
|
|
|
|
#define BUF_SIZE 120 /* 20 milliseconds == 120 bytes, 640 samples */
|
|
#define SAMPLES_TO_BYTES(x) ((typeof(x)) x / ((float) 640 / 120))
|
|
#define BYTES_TO_SAMPLES(x) ((typeof(x)) x * ((float) 640 / 120))
|
|
|
|
static struct ast_frame *siren14read(struct ast_filestream *s, int *whennext)
|
|
{
|
|
size_t res;
|
|
|
|
/* Send a frame from the file to the appropriate channel */
|
|
AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
|
|
if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
|
|
if (res) {
|
|
ast_log(LOG_WARNING, "Short read of %s data (expected %d bytes, read %zu): %s\n",
|
|
ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res,
|
|
strerror(errno));
|
|
}
|
|
return NULL;
|
|
}
|
|
*whennext = s->fr.samples = BYTES_TO_SAMPLES(res);
|
|
return &s->fr;
|
|
}
|
|
|
|
static int siren14write(struct ast_filestream *fs, struct ast_frame *f)
|
|
{
|
|
int res;
|
|
|
|
if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
|
|
ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int siren14seek(struct ast_filestream *fs, off_t sample_offset, int whence)
|
|
{
|
|
off_t offset = 0, min = 0, cur, max;
|
|
|
|
sample_offset = SAMPLES_TO_BYTES(sample_offset);
|
|
|
|
if ((cur = ftello(fs->f)) < 0) {
|
|
ast_log(AST_LOG_WARNING, "Unable to determine current position in siren14 filestream %p: %s\n", fs, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (fseeko(fs->f, 0, SEEK_END) < 0) {
|
|
ast_log(AST_LOG_WARNING, "Unable to seek to end of siren14 filestream %p: %s\n", fs, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if ((max = ftello(fs->f)) < 0) {
|
|
ast_log(AST_LOG_WARNING, "Unable to determine max position in siren14 filestream %p: %s\n", fs, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (whence == SEEK_SET)
|
|
offset = sample_offset;
|
|
else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
|
|
offset = sample_offset + cur;
|
|
else if (whence == SEEK_END)
|
|
offset = max - sample_offset;
|
|
|
|
if (whence != SEEK_FORCECUR)
|
|
offset = (offset > max) ? max : offset;
|
|
|
|
/* always protect against seeking past begining. */
|
|
offset = (offset < min) ? min : offset;
|
|
|
|
return fseeko(fs->f, offset, SEEK_SET);
|
|
}
|
|
|
|
static int siren14trunc(struct ast_filestream *fs)
|
|
{
|
|
int fd;
|
|
off_t cur;
|
|
|
|
if ((fd = fileno(fs->f)) < 0) {
|
|
ast_log(AST_LOG_WARNING, "Unable to determine file descriptor for siren14 filestream %p: %s\n", fs, strerror(errno));
|
|
return -1;
|
|
}
|
|
if ((cur = ftello(fs->f)) < 0) {
|
|
ast_log(AST_LOG_WARNING, "Unable to determine current position in siren14 filestream %p: %s\n", fs, strerror(errno));
|
|
return -1;
|
|
}
|
|
/* Truncate file to current length */
|
|
return ftruncate(fd, cur);
|
|
}
|
|
|
|
static off_t siren14tell(struct ast_filestream *fs)
|
|
{
|
|
return BYTES_TO_SAMPLES(ftello(fs->f));
|
|
}
|
|
|
|
static struct ast_format_def siren14_f = {
|
|
.name = "siren14",
|
|
.exts = "siren14",
|
|
.write = siren14write,
|
|
.seek = siren14seek,
|
|
.trunc = siren14trunc,
|
|
.tell = siren14tell,
|
|
.read = siren14read,
|
|
.buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
|
|
};
|
|
|
|
static int load_module(void)
|
|
{
|
|
siren14_f.format = ast_format_siren14;
|
|
if (ast_format_def_register(&siren14_f))
|
|
return AST_MODULE_LOAD_DECLINE;
|
|
|
|
return AST_MODULE_LOAD_SUCCESS;
|
|
}
|
|
|
|
static int unload_module(void)
|
|
{
|
|
return ast_format_def_unregister(siren14_f.name);
|
|
}
|
|
|
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ITU G.722.1 Annex C (Siren14, licensed from Polycom)",
|
|
.support_level = AST_MODULE_SUPPORT_CORE,
|
|
.load = load_module,
|
|
.unload = unload_module,
|
|
.load_pri = AST_MODPRI_APP_DEPEND
|
|
);
|