o split AmAudioFile from AmAudio in extra file

o added codec module init/destroy functions
o fixed re-creating codec instance on file open
o added unlimited data_size option on RO files 


git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@708 8eb893ce-cfd4-0310-b710-fb5ebe64c474
sayer/1.4-spce2.6
Stefan Sayer 19 years ago
parent 42ab9d76e7
commit 20e1dd182f

@ -142,35 +142,24 @@ AmAudioSimpleFormat::AmAudioSimpleFormat(int codec_id)
channels = 1;
}
AmAudioFileFormat::AmAudioFileFormat(const string& name, int subtype)
: name(name), subtype(subtype), p_subtype(0)
{
getSubtype();
codec = getCodec();
if(p_subtype && codec){
rate = p_subtype->sample_rate;
channels = p_subtype->channels;
subtype = p_subtype->type;
}
}
AmAudioFormat::~AmAudioFormat()
{
destroyCodec();
}
unsigned int AmAudioFormat::samples2bytes(unsigned int nb_samples) const
unsigned int AmAudioFormat::calcBytesToRead(unsigned int needed_samples) const
{
if (codec && codec->samples2bytes)
return codec->samples2bytes(h_codec, nb_samples) * channels;
return codec->samples2bytes(h_codec, needed_samples) * channels; // FIXME: channels
WARN("Cannot convert samples to bytes\n");
return nb_samples * channels;
return needed_samples * channels;
}
unsigned int AmAudioFormat::bytes2samples(unsigned int bytes) const
{
if (codec && codec->samples2bytes)
if (codec && codec->bytes2samples)
return codec->bytes2samples(h_codec, bytes) / channels;
WARN("Cannot convert bytes to samples\n");
return bytes / channels;
@ -232,27 +221,6 @@ void AmAudioFormat::destroyCodec()
codec = NULL;
}
amci_subtype_t* AmAudioFileFormat::getSubtype()
{
if(!p_subtype && !name.empty()){
amci_inoutfmt_t* iofmt = AmPlugIn::instance()->fileFormat(name.c_str());
if(!iofmt){
ERROR("AmAudioFileFormat::getSubtype: file format '%s' does not exist\n",
name.c_str());
throw string("AmAudioFileFormat::getSubtype: file format '%s' does not exist\n");
}
else {
p_subtype = AmPlugIn::instance()->subtype(iofmt,subtype);
if(!p_subtype)
ERROR("AmAudioFileFormat::getSubtype: subtype %i in format '%s' does not exist\n",
subtype,iofmt->name);
subtype = p_subtype->type;
}
}
return p_subtype;
}
amci_codec_t* AmAudioFormat::getCodec()
{
@ -299,7 +267,7 @@ void AmAudio::close()
// returns bytes read, else -1 if error (0 is OK)
int AmAudio::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples)
{
int size = samples2bytes(nb_samples);
int size = calcBytesToRead(nb_samples);
size = read(user_ts,size);
//DBG("size = %d\n",size);
@ -428,9 +396,9 @@ unsigned int AmAudio::getFrameSize()
return fmt->frame_size;
}
unsigned int AmAudio::samples2bytes(unsigned int nb_samples) const
unsigned int AmAudio::calcBytesToRead(unsigned int nb_samples) const
{
return fmt->samples2bytes(nb_samples);
return fmt->calcBytesToRead(nb_samples);
}
unsigned int AmAudio::bytes2samples(unsigned int bytes) const
@ -469,326 +437,6 @@ void DblBuffer::swap()
active_buf = !active_buf;
}
// returns 0 if everything's OK
// return -1 if error
int AmAudioFile::open(const string& filename, OpenMode mode, bool is_tmp)
{
close();
AmAudioFileFormat* f_fmt = fileName2Fmt(filename);
if(!f_fmt){
ERROR("while trying to the format of '%s'\n",filename.c_str());
return -1;
}
fmt.reset(f_fmt);
open_mode = mode;
this->close_on_exit = true;
if(!is_tmp){
fp = fopen(filename.c_str(),mode == AmAudioFile::Read ? "r" : "w+");
if(!fp){
if(mode == AmAudioFile::Read)
ERROR("file not found: %s\n",filename.c_str());
else
ERROR("could not create/overwrite file: %s\n",filename.c_str());
return -1;
}
} else {
fp = tmpfile();
if(!fp){
ERROR("could not create temporary file: %s\n",strerror(errno));
}
}
amci_file_desc_t fd;
int ret = -1;
if(open_mode == AmAudioFile::Write){
if (f_fmt->channels<0 || f_fmt->rate<0) {
if (f_fmt->channels<0)
ERROR("channel count must be set for output file.\n");
if (f_fmt->rate<0)
ERROR("sampling rate must be set for output file.\n");
close();
return -1;
}
}
fd.subtype = f_fmt->getSubtypeId();
fd.channels = f_fmt->channels;
fd.rate = f_fmt->rate;
if( iofmt->open && !(ret = (*iofmt->open)(fp,&fd,mode, f_fmt->getHCodecNoInit())) ) {
if (mode == AmAudioFile::Read) {
f_fmt->setSubtypeId(fd.subtype);
f_fmt->channels = fd.channels;
f_fmt->rate = fd.rate;
data_size = fd.data_size;
}
begin = ftell(fp);
}
else {
if(!iofmt->open)
ERROR("no open function\n");
else
ERROR("open returned %d\n",ret);
close();
return ret;
}
// if(open_mode == AmAudioFile::Write){
// DBG("After open:\n");
// DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
// DBG("fmt::sample = %i\n",f_fmt->sample);
// DBG("fmt::channels = %i\n",f_fmt->channels);
// DBG("fmt::rate = %i\n",f_fmt->rate);
// }
return ret;
}
int AmAudioFile::fpopen(const string& filename, OpenMode mode, FILE* n_fp)
{
close();
AmAudioFileFormat* f_fmt = fileName2Fmt(filename);
if(!f_fmt){
ERROR("while trying to the format of '%s'\n",filename.c_str());
return -1;
}
fmt.reset(f_fmt);
open_mode = mode;
fp = n_fp;
fseek(fp,0L,SEEK_SET);
amci_file_desc_t fd;
int ret = -1;
if(open_mode == AmAudioFile::Write){
if (f_fmt->channels<0 || f_fmt->rate<0) {
if (f_fmt->channels<0)
ERROR("channel count must be set for output file.\n");
if (f_fmt->rate<0)
ERROR("sampling rate must be set for output file.\n");
close();
return -1;
}
}
fd.subtype = f_fmt->getSubtypeId();
fd.channels = f_fmt->channels;
fd.rate = f_fmt->rate;
if( iofmt->open && !(ret = (*iofmt->open)(fp,&fd,mode, f_fmt->getHCodecNoInit())) ) {
if (mode == AmAudioFile::Read) {
f_fmt->setSubtypeId(fd.subtype);
f_fmt->channels = fd.channels;
f_fmt->rate = fd.rate;
data_size = fd.data_size;
}
begin = ftell(fp);
}
else {
if(!iofmt->open)
ERROR("no open function\n");
else
ERROR("open returned %d\n",ret);
close();
return ret;
}
// if(open_mode == AmAudioFile::Write){
// DBG("After open:\n");
// DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
// DBG("fmt::channels = %i\n",f_fmt->channels);
// DBG("fmt::rate = %i\n",f_fmt->rate);
// }
return ret;
}
AmAudioFile::AmAudioFile()
: AmAudio(), data_size(0),
fp(0), begin(0), loop(false),
on_close_done(false),
close_on_exit(true)
{
}
AmAudioFile::~AmAudioFile()
{
close();
}
void AmAudioFile::rewind()
{
fseek(fp,begin,SEEK_SET);
}
void AmAudioFile::on_close()
{
if(fp && !on_close_done){
AmAudioFileFormat* f_fmt =
dynamic_cast<AmAudioFileFormat*>(fmt.get());
if(f_fmt){
amci_file_desc_t fmt_desc = { f_fmt->getSubtypeId(),
f_fmt->rate,
f_fmt->channels,
data_size };
if(!iofmt){
ERROR("file format pointer not initialized: on_close will not be called\n");
}
else if(iofmt->on_close)
(*iofmt->on_close)(fp,&fmt_desc,open_mode, fmt->getHCodecNoInit(), fmt->getCodec());
}
if(open_mode == AmAudioFile::Write){
DBG("After close:\n");
DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
DBG("fmt::channels = %i\n",f_fmt->channels);
DBG("fmt::rate = %i\n",f_fmt->rate);
}
on_close_done = true;
}
}
void AmAudioFile::close()
{
if(fp){
on_close();
if(close_on_exit)
fclose(fp);
fp = 0;
}
}
string AmAudioFile::getMimeType()
{
if(!iofmt)
return "";
return iofmt->email_content_type;
}
int AmAudioFile::read(unsigned int user_ts, unsigned int size)
{
if(!fp){
ERROR("AmAudioFile::read: file is not opened\n");
return -1;
}
int ret;
int s = size;
read_block:
long fpos = ftell(fp);
if(fpos - begin < data_size){
if(fpos - begin + (int)size > data_size){
s = data_size - fpos + begin;
}
s = fread((void*)((unsigned char*)samples),1,s,fp);
ret = (!ferror(fp) ? s : -1);
#if __BYTE_ORDER == __BIG_ENDIAN
#define bswap_16(A) ((((u_int16_t)(A) & 0xff00) >> 8) | \
(((u_int16_t)(A) & 0x00ff) << 8))
unsigned int i;
for(i=0;i<=size/2;i++) {
u_int16_t *tmp;
((u_int16_t *)((unsigned char*)samples))[i]=bswap_16(((u_int16_t *)((unsigned char*)samples))[i]);
}
#endif
}
else {
if(loop.get() && data_size>0){
DBG("rewinding audio file...\n");
rewind();
goto read_block;
}
ret = -2; // eof
}
if(ret > 0 && s > 0 && (unsigned int)s < size){
DBG("0-stuffing packet: adding %i bytes (packet size=%i)\n",size-s,size);
memset((unsigned char*)samples + s,0,size-s);
return size;
}
return ret;
}
int AmAudioFile::write(unsigned int user_ts, unsigned int size)
{
if(!fp){
ERROR("AmAudioFile::write: file is not opened\n");
return -1;
}
int s = fwrite((void*)((unsigned char*)samples),1,size,fp);
if(s>0)
data_size += s;
return (!ferror(fp) ? s : -1);
}
int AmAudioFile::getLength()
{
if (!data_size || !fmt.get())
return 0;
return
fmt->bytes2samples(data_size) /
(fmt->rate/1000);
}
AmAudioFileFormat* AmAudioFile::fileName2Fmt(const string& name)
{
string ext = file_extension(name);
if(ext == ""){
ERROR("fileName2Fmt: file name has no extension (%s)",name.c_str());
return NULL;
}
iofmt = AmPlugIn::instance()->fileFormat("",ext);
if(!iofmt){
ERROR("fileName2Fmt: could not find a format with that extension: '%s'",ext.c_str());
return NULL;
}
return new AmAudioFileFormat(iofmt->name);
}
int AmAudioFileFormat::getCodecId()
{
if(!name.empty()){
getSubtype();
if(p_subtype)
return p_subtype->codec_id;
}
return -1;
}
int AmAudioRtpFormat::getCodecId()

@ -123,7 +123,7 @@ public:
long getHCodec();
long getHCodecNoInit() { return h_codec; } // do not initialize
unsigned int samples2bytes(unsigned int) const;
unsigned int calcBytesToRead(unsigned int needed_samples) const;
unsigned int bytes2samples(unsigned int) const;
/** @return true if same format. */
@ -160,52 +160,6 @@ public:
AmAudioSimpleFormat(int codec_id);
};
/** \brief \ref AmAudioFormat for file */
class AmAudioFileFormat: public AmAudioFormat
{
/** == "" if not yet initialized. */
string name;
/** == -1 if not yet initialized. */
int subtype;
/** == 0 if not yet initialized. */
amci_subtype_t* p_subtype;
protected:
int getCodecId();
public:
/**
* Constructor for file based formats.
* All information are taken from the plug-in description.
* @param name The file format name (ex. "Wav").
* @param subtype Subtype for the file format (see amci.h).
*/
AmAudioFileFormat(const string& name, int subtype = -1);
/**
* Constructor for file based formats.
* All information are taken from the file descriptor.
* @param name The file format name (ex. "Wav").
* @param fd A file descriptor filled by the a plug-in's open function.
*/
AmAudioFileFormat(const string& name, const amci_file_desc_t* fd);
/** @return Format name. */
string getName() { return name; }
/** @return Format subtype. */
int getSubtypeId() { return subtype; }
/** @return Subtype pointer. */
amci_subtype_t* getSubtype();
void setSubtypeId(int subtype_id)
{
destroyCodec();
subtype = subtype_id;
p_subtype = 0;
codec = getCodec();
}
};
/** \brief RTP audio format */
class AmAudioRtpFormat: public AmAudioFormat
@ -294,9 +248,9 @@ protected:
unsigned int downMix(unsigned int size);
/**
* Convert the size from samples to bytes, depending on the format.
* Get the number of bytes to read from encoded, depending on the format.
*/
unsigned int samples2bytes(unsigned int nb_samples) const;
unsigned int calcBytesToRead(unsigned int needed_samples) const;
/**
* Convert the size from bytes to samples, depending on the format.
@ -335,97 +289,6 @@ public:
int incRecordTime(unsigned int samples);
};
/**
* \brief AmAudio implementation for file access
*/
class AmAudioFile: public AmAudio
{
public:
/** Open mode. */
enum OpenMode { Read=1, Write=2 };
protected:
/** Pointer to the file opened as last. */
FILE* fp;
long begin;
/** Format of that file. @see fp, open(). */
amci_inoutfmt_t* iofmt;
/** Open mode. */
int open_mode;
/** Size of datas having been read/written until now. */
int data_size;
bool on_close_done;
bool close_on_exit;
/** @see AmAudio::read */
int read(unsigned int user_ts, unsigned int size);
/** @see AmAudio::write */
int write(unsigned int user_ts, unsigned int size);
/** @return a file format from file name. (ex: '1234.wav') */
AmAudioFileFormat* fileName2Fmt(const string& name);
public:
AmSharedVar<bool> loop;
AmAudioFile();
~AmAudioFile();
/**
* Opens a file.
* <ul>
* <li>In read mode: sets input format.
* <li>In write mode: <ol>
* <li>needs output format set.
* <li>If file name already exists,
* the file will be overwritten.
* </ol>
* </ul>
* @param filename Name of the file.
* @param mode Open mode.
* @return 0 if everything's OK
* @see OpenMode
*/
int open(const string& filename, OpenMode mode,
bool is_tmp=false);
int fpopen(const string& filename, OpenMode mode, FILE* n_fp);
/**
* Rewind the file.
*/
void rewind();
/** Closes the file. */
void close();
/** Executes the handler's on_close. */
void on_close();
/** be carefull with this one ;-) */
FILE* getfp() { return fp; }
OpenMode getMode() { return (OpenMode)open_mode; }
/** Gets data size in the current file */
int getDataSize() { return data_size; }
/** Gets length of the current file in ms */
int getLength();
/**
* @return MIME type corresponding to the audio file.
*/
string getMimeType();
void setCloseOnDestroy(bool cod){
close_on_exit = cod;
}
};
#endif

@ -0,0 +1,402 @@
/*
* $Id: AmAudio.cpp 633 2008-01-28 18:17:36Z sayer $
*
* Copyright (C) 2002-2003 Fhg Fokus
*
* This file is part of sems, a free SIP media server.
*
* sems is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "AmAudioFile.h"
#include "AmPlugIn.h"
#include "AmUtils.h"
#include <string.h>
AmAudioFileFormat::AmAudioFileFormat(const string& name, int subtype)
: name(name), subtype(subtype), p_subtype(0)
{
getSubtype();
codec = getCodec();
if(p_subtype && codec){
rate = p_subtype->sample_rate;
channels = p_subtype->channels;
subtype = p_subtype->type;
}
}
void AmAudioFileFormat::setSubtypeId(int subtype_id) {
if (subtype != subtype_id) {
DBG("changing file subtype to ID %d\n", subtype_id);
destroyCodec();
subtype = subtype_id;
p_subtype = 0;
codec = getCodec();
}
}
amci_subtype_t* AmAudioFileFormat::getSubtype()
{
if(!p_subtype && !name.empty()){
amci_inoutfmt_t* iofmt = AmPlugIn::instance()->fileFormat(name.c_str());
if(!iofmt){
ERROR("AmAudioFileFormat::getSubtype: file format '%s' does not exist\n",
name.c_str());
throw string("AmAudioFileFormat::getSubtype: file format '%s' does not exist\n");
}
else {
p_subtype = AmPlugIn::instance()->subtype(iofmt,subtype);
if(!p_subtype)
ERROR("AmAudioFileFormat::getSubtype: subtype %i in format '%s' does not exist\n",
subtype,iofmt->name);
subtype = p_subtype->type;
}
}
return p_subtype;
}
AmAudioFileFormat* AmAudioFile::fileName2Fmt(const string& name)
{
string ext = file_extension(name);
if(ext == ""){
ERROR("fileName2Fmt: file name has no extension (%s)\n",name.c_str());
return NULL;
}
iofmt = AmPlugIn::instance()->fileFormat("",ext);
if(!iofmt){
ERROR("fileName2Fmt: could not find a format with that extension: '%s'\n",ext.c_str());
return NULL;
}
return new AmAudioFileFormat(iofmt->name);
}
int AmAudioFileFormat::getCodecId()
{
if(!name.empty()){
getSubtype();
if(p_subtype)
return p_subtype->codec_id;
}
return -1;
}
// returns 0 if everything's OK
// return -1 if error
int AmAudioFile::open(const string& filename, OpenMode mode, bool is_tmp)
{
close();
AmAudioFileFormat* f_fmt = fileName2Fmt(filename);
if(!f_fmt){
ERROR("while trying to the format of '%s'\n",filename.c_str());
return -1;
}
fmt.reset(f_fmt);
open_mode = mode;
this->close_on_exit = true;
if(!is_tmp){
fp = fopen(filename.c_str(),mode == AmAudioFile::Read ? "r" : "w+");
if(!fp){
if(mode == AmAudioFile::Read)
ERROR("file not found: %s\n",filename.c_str());
else
ERROR("could not create/overwrite file: %s\n",filename.c_str());
return -1;
}
} else {
fp = tmpfile();
if(!fp){
ERROR("could not create temporary file: %s\n",strerror(errno));
}
}
amci_file_desc_t fd;
int ret = -1;
if(open_mode == AmAudioFile::Write){
if (f_fmt->channels<0 || f_fmt->rate<0) {
if (f_fmt->channels<0)
ERROR("channel count must be set for output file.\n");
if (f_fmt->rate<0)
ERROR("sampling rate must be set for output file.\n");
close();
return -1;
}
}
fd.subtype = f_fmt->getSubtypeId();
fd.channels = f_fmt->channels;
fd.rate = f_fmt->rate;
if( iofmt->open && !(ret = (*iofmt->open)(fp, &fd, mode, f_fmt->getHCodecNoInit())) ) {
if (mode == AmAudioFile::Read) {
f_fmt->setSubtypeId(fd.subtype);
f_fmt->channels = fd.channels;
f_fmt->rate = fd.rate;
data_size = fd.data_size;
}
begin = ftell(fp);
}
else {
if(!iofmt->open)
ERROR("no open function\n");
else
ERROR("open returned %d\n",ret);
close();
return ret;
}
// if(open_mode == AmAudioFile::Write){
// DBG("After open:\n");
// DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
// DBG("fmt::sample = %i\n",f_fmt->sample);
// DBG("fmt::channels = %i\n",f_fmt->channels);
// DBG("fmt::rate = %i\n",f_fmt->rate);
// }
return ret;
}
int AmAudioFile::fpopen(const string& filename, OpenMode mode, FILE* n_fp)
{
close();
AmAudioFileFormat* f_fmt = fileName2Fmt(filename);
if(!f_fmt){
ERROR("while trying to the format of '%s'\n",filename.c_str());
return -1;
}
fmt.reset(f_fmt);
open_mode = mode;
fp = n_fp;
fseek(fp,0L,SEEK_SET);
amci_file_desc_t fd;
int ret = -1;
if(open_mode == AmAudioFile::Write){
if (f_fmt->channels<0 || f_fmt->rate<0) {
if (f_fmt->channels<0)
ERROR("channel count must be set for output file.\n");
if (f_fmt->rate<0)
ERROR("sampling rate must be set for output file.\n");
close();
return -1;
}
}
fd.subtype = f_fmt->getSubtypeId();
fd.channels = f_fmt->channels;
fd.rate = f_fmt->rate;
if( iofmt->open && !(ret = (*iofmt->open)(fp,&fd,mode, f_fmt->getHCodecNoInit())) ) {
if (mode == AmAudioFile::Read) {
f_fmt->setSubtypeId(fd.subtype);
f_fmt->channels = fd.channels;
f_fmt->rate = fd.rate;
data_size = fd.data_size;
}
begin = ftell(fp);
}
else {
if(!iofmt->open)
ERROR("no open function\n");
else
ERROR("open returned %d\n",ret);
close();
return ret;
}
// if(open_mode == AmAudioFile::Write){
// DBG("After open:\n");
// DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
// DBG("fmt::channels = %i\n",f_fmt->channels);
// DBG("fmt::rate = %i\n",f_fmt->rate);
// }
return ret;
}
AmAudioFile::AmAudioFile()
: AmAudio(), data_size(0),
fp(0), begin(0), loop(false),
on_close_done(false),
close_on_exit(true)
{
}
AmAudioFile::~AmAudioFile()
{
close();
}
void AmAudioFile::rewind()
{
fseek(fp,begin,SEEK_SET);
}
void AmAudioFile::on_close()
{
if(fp && !on_close_done){
AmAudioFileFormat* f_fmt =
dynamic_cast<AmAudioFileFormat*>(fmt.get());
if(f_fmt){
amci_file_desc_t fmt_desc = { f_fmt->getSubtypeId(),
f_fmt->rate,
f_fmt->channels,
data_size };
if(!iofmt){
ERROR("file format pointer not initialized: on_close will not be called\n");
}
else if(iofmt->on_close)
(*iofmt->on_close)(fp,&fmt_desc,open_mode, fmt->getHCodecNoInit(), fmt->getCodec());
}
if(open_mode == AmAudioFile::Write){
DBG("After close:\n");
DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
DBG("fmt::channels = %i\n",f_fmt->channels);
DBG("fmt::rate = %i\n",f_fmt->rate);
}
on_close_done = true;
}
}
void AmAudioFile::close()
{
if(fp){
on_close();
if(close_on_exit)
fclose(fp);
fp = 0;
}
}
string AmAudioFile::getMimeType()
{
if(!iofmt)
return "";
return iofmt->email_content_type;
}
int AmAudioFile::read(unsigned int user_ts, unsigned int size)
{
if(!fp){
ERROR("AmAudioFile::read: file is not opened\n");
return -1;
}
int ret;
int s = size;
read_block:
long fpos = ftell(fp);
if(data_size < 0 || fpos - begin < data_size){
if((data_size > 0) && (fpos - begin + (int)size > data_size)){
s = data_size - fpos + begin;
}
s = fread((void*)((unsigned char*)samples),1,s,fp);
ret = (!ferror(fp) ? s : -1);
#if __BYTE_ORDER == __BIG_ENDIAN
#define bswap_16(A) ((((u_int16_t)(A) & 0xff00) >> 8) | \
(((u_int16_t)(A) & 0x00ff) << 8))
unsigned int i;
for(i=0;i<=size/2;i++) {
u_int16_t *tmp;
((u_int16_t *)((unsigned char*)samples))[i]=bswap_16(((u_int16_t *)((unsigned char*)samples))[i]);
}
#endif
}
else {
if(loop.get() && data_size>0){
DBG("rewinding audio file...\n");
rewind();
goto read_block;
}
ret = -2; // eof
}
if(ret > 0 && s > 0 && (unsigned int)s < size){
DBG("0-stuffing packet: adding %i bytes (packet size=%i)\n",size-s,size);
memset((unsigned char*)samples + s,0,size-s);
return size;
}
return ret;
}
int AmAudioFile::write(unsigned int user_ts, unsigned int size)
{
if(!fp){
ERROR("AmAudioFile::write: file is not opened\n");
return -1;
}
int s = fwrite((void*)((unsigned char*)samples),1,size,fp);
if(s>0)
data_size += s;
return (!ferror(fp) ? s : -1);
}
int AmAudioFile::getLength()
{
if (!data_size || !fmt.get())
return 0;
return
fmt->bytes2samples(data_size) /
(fmt->rate/1000);
}

@ -0,0 +1,170 @@
/*
* $Id: AmAudio.h 633 2008-01-28 18:17:36Z sayer $
*
* Copyright (C) 2002-2003 Fhg Fokus
*
* This file is part of sems, a free SIP media server.
*
* sems is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* sems is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file AmAudioFile.h */
#ifndef _AmAudioFile_h_
#define _AmAudioFile_h_
#include "AmAudio.h"
/** \brief \ref AmAudioFormat for file */
class AmAudioFileFormat: public AmAudioFormat
{
/** == "" if not yet initialized. */
string name;
/** == -1 if not yet initialized. */
int subtype;
/** == 0 if not yet initialized. */
amci_subtype_t* p_subtype;
protected:
int getCodecId();
public:
/**
* Constructor for file based formats.
* All information are taken from the plug-in description.
* @param name The file format name (ex. "Wav").
* @param subtype Subtype for the file format (see amci.h).
*/
AmAudioFileFormat(const string& name, int subtype = -1);
/**
* Constructor for file based formats.
* All information are taken from the file descriptor.
* @param name The file format name (ex. "Wav").
* @param fd A file descriptor filled by the a plug-in's open function.
*/
AmAudioFileFormat(const string& name, const amci_file_desc_t* fd);
/** @return Format name. */
string getName() { return name; }
/** @return Format subtype. */
int getSubtypeId() { return subtype; }
/** @return Subtype pointer. */
amci_subtype_t* getSubtype();
void setSubtypeId(int subtype_id);
};
/**
* \brief AmAudio implementation for file access
*/
class AmAudioFile: public AmAudio
{
public:
/** Open mode. */
enum OpenMode { Read=1, Write=2 };
protected:
/** Pointer to the file opened as last. */
FILE* fp;
long begin;
/** Format of that file. @see fp, open(). */
amci_inoutfmt_t* iofmt;
/** Open mode. */
int open_mode;
/** Size of datas having been read/written until now. */
int data_size;
bool on_close_done;
bool close_on_exit;
/** @see AmAudio::read */
int read(unsigned int user_ts, unsigned int size);
/** @see AmAudio::write */
int write(unsigned int user_ts, unsigned int size);
/** @return a file format from file name. (ex: '1234.wav') */
AmAudioFileFormat* fileName2Fmt(const string& name);
public:
AmSharedVar<bool> loop;
AmAudioFile();
~AmAudioFile();
/**
* Opens a file.
* <ul>
* <li>In read mode: sets input format.
* <li>In write mode: <ol>
* <li>needs output format set.
* <li>If file name already exists,
* the file will be overwritten.
* </ol>
* </ul>
* @param filename Name of the file.
* @param mode Open mode.
* @return 0 if everything's OK
* @see OpenMode
*/
int open(const string& filename, OpenMode mode,
bool is_tmp=false);
int fpopen(const string& filename, OpenMode mode, FILE* n_fp);
/**
* Rewind the file.
*/
void rewind();
/** Closes the file. */
void close();
/** Executes the handler's on_close. */
void on_close();
/** be carefull with this one ;-) */
FILE* getfp() { return fp; }
OpenMode getMode() { return (OpenMode)open_mode; }
/** Gets data size in the current file */
int getDataSize() { return data_size; }
/** Gets length of the current file in ms */
int getLength();
/**
* @return MIME type corresponding to the audio file.
*/
string getMimeType();
void setCloseOnDestroy(bool cod){
close_on_exit = cod;
}
};
#endif
// Local Variables:
// mode:C++
// End:

@ -29,6 +29,7 @@
#define _AM_AUDIO_MIX_IN_H
#include "AmAudio.h"
#include "AmAudioFile.h"
#define MAX_PACKETLENGTH_MS 30

@ -28,7 +28,7 @@
#ifndef _AMFILECACHE_H
#define _AMFILECACHE_H
#include "AmAudio.h"
#include "AmAudioFile.h"
#include <string>

@ -80,7 +80,7 @@ int AmPlaylist::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb
}
if(!cur_item || !cur_item->play) {
ret = samples2bytes(nb_samples);
ret = calcBytesToRead(nb_samples);
memset(buffer,0,ret);
}

@ -450,6 +450,13 @@ int AmPlugIn::loadAudioPlugIn(amci_exports_t* exports)
return -1;
}
if (exports->module_load) {
if (exports->module_load() < 0) {
ERROR("initializing audio plug-in!\n");
return -1;
}
}
for( amci_codec_t* c=exports->codecs;
c->id>=0; c++ ){

@ -90,7 +90,7 @@ struct amci_file_desc_t {
/** # channels */
int channels;
/** size of the data */
/** size of the data. -1 for unknown/unlimited */
int data_size;
};
@ -98,7 +98,7 @@ struct amci_file_desc_t {
* \brief Sound converter function pointer.
* @param out [out] output buffer
* @param in [in] input buffer
* @param size [in] size of input buffer
* @param size [in] size of input buffer
* @param channels [in] number of channels
* @param rate [in] sampling rate
* @param h_codec [in] codec handle
@ -208,6 +208,19 @@ typedef int (*amci_file_mem_close_t)( unsigned char* mptr,
struct amci_codec_t *codec
);
/**
* \brief Codec module 's init function pointer.
* this function initializes the codec module.
* @return 0 on success, <0 on error
*/
typedef int (*amci_codec_module_load_t)(void);
/**
* \brief Codec's module's destroy function pointer.
*/
typedef void (*amci_codec_module_destroy_t)(void);
/**
* \brief Codec's init function pointer.
*
@ -217,7 +230,7 @@ typedef int (*amci_file_mem_close_t)( unsigned char* mptr,
* <tr><td>AMCI_FMT_FRAME_LENGTH (1)</td><td> frame length in ms (for framed codecs; must be multiple of 10)</td></tr>
* <tr><td>AMCI_FMT_FRAME_SIZE (2)</td><td> frame size in samples</td></tr>
* <tr><td>AMCI_FMT_ENCODED_FRAME_SIZE (3)</td><td> encoded frame size</td></tr></table>
* @return -1 if failed, else some handler which will be
* @return -1 if failed, else some handle which will be
* passed by each further call (0 is legal).
*
*/
@ -262,7 +275,7 @@ struct amci_codec_t {
/** Does the opposite of encode. */
amci_converter_t decode;
/** Codec specific packet loss concealment. */
/** Codec specific packet loss concealment. can be NULL */
amci_plc_t plc;
/** Init function. can be NULL. */
@ -382,6 +395,11 @@ struct amci_exports_t {
/** Module name */
char* name;
/** Codec module load function. can be NULL */
amci_codec_module_load_t module_load;
/** Codec module destroy function. can be NULL */
amci_codec_module_destroy_t module_destroy;
/** NULL terminated array of amci_codec_t */
struct amci_codec_t* codecs;
/** NULL terminated array of amci_payload_t */
@ -397,9 +415,12 @@ struct amci_exports_t {
* see example media plug-in 'wav' (plug-in/wav/wav.c).
* @hideinitializer
*/
#define BEGIN_EXPORTS(name) \
#define BEGIN_EXPORTS(name, module_load, module_destroy) \
struct amci_exports_t amci_exports = { \
name,
name,\
module_load,\
module_destroy,
/**
* Portable export definition macro
@ -431,7 +452,7 @@ struct amci_exports_t {
* see example media plug-in 'wav' (plug-in/wav/wav.c).
* @hideinitializer
*/
#define CODEC(id,intern2type,type2intern,plc,init,destroy,bytes2samples,samples2bytes) \
#define CODEC(id, intern2type,type2intern,plc,init,destroy,bytes2samples,samples2bytes) \
{ id, intern2type, type2intern, plc, init, destroy, bytes2samples, samples2bytes },
/**
@ -520,6 +541,13 @@ struct amci_exports_t {
{ type, name, rate, channels, codec_id },
/* defines to make definitions more expressive */
#define AMCI_NO_MODULEINIT NULL
#define AMCI_NO_MODULEDESTROY NULL
#define AMCI_NO_CODEC_PLC NULL
#define AMCI_NO_CODECCREATE NULL
#define AMCI_NO_CODECDESTROY NULL
#ifdef __cplusplus
}
#endif

@ -77,16 +77,16 @@ static unsigned int g726_40_bytes2samples(long, unsigned int);
static unsigned int g726_40_samples2bytes(long, unsigned int);
BEGIN_EXPORTS( "adpcm" )
BEGIN_EXPORTS( "adpcm", AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY)
BEGIN_CODECS
CODEC( CODEC_G726_16, Pcm16_2_G726_16, G726_16_2_Pcm16, NULL,
CODEC( CODEC_G726_16, Pcm16_2_G726_16, G726_16_2_Pcm16, AMCI_NO_CODEC_PLC,
G726_create, G726_destroy, g726_16_bytes2samples, g726_16_samples2bytes )
CODEC( CODEC_G726_24, Pcm16_2_G726_24, G726_24_2_Pcm16, NULL,
CODEC( CODEC_G726_24, Pcm16_2_G726_24, G726_24_2_Pcm16, AMCI_NO_CODEC_PLC,
G726_create, G726_destroy, g726_24_bytes2samples, g726_24_samples2bytes )
CODEC( CODEC_G726_32, Pcm16_2_G726_32, G726_32_2_Pcm16, NULL,
CODEC( CODEC_G726_32, Pcm16_2_G726_32, G726_32_2_Pcm16, AMCI_NO_CODEC_PLC,
G726_create, G726_destroy, g726_32_bytes2samples, g726_32_samples2bytes )
CODEC( CODEC_G726_40, Pcm16_2_G726_40, G726_40_2_Pcm16, NULL,
CODEC( CODEC_G726_40, Pcm16_2_G726_40, G726_40_2_Pcm16, AMCI_NO_CODEC_PLC,
G726_create, G726_destroy, g726_40_bytes2samples, g726_40_samples2bytes )
END_CODECS

@ -46,10 +46,10 @@ static void gsm_destroy_if(long h_codec);
static unsigned int gsm_bytes2samples(long, unsigned int);
static unsigned int gsm_samples2bytes(long, unsigned int);
BEGIN_EXPORTS( "gsm" )
BEGIN_EXPORTS( "gsm", AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
BEGIN_CODECS
CODEC( CODEC_GSM0610, pcm16_2_gsm, gsm_2_pcm16, NULL,
CODEC( CODEC_GSM0610, pcm16_2_gsm, gsm_2_pcm16, AMCI_NO_CODEC_PLC,
gsm_create_if, (amci_codec_destroy_t)gsm_destroy_if, gsm_bytes2samples, gsm_samples2bytes )
END_CODECS

@ -77,7 +77,7 @@ static int iLBC_close(FILE* fp, struct amci_file_desc_t* fmt_desc, int options,
static unsigned int ilbc_bytes2samples(long, unsigned int);
static unsigned int ilbc_samples2bytes(long, unsigned int);
BEGIN_EXPORTS( "ilbc" )
BEGIN_EXPORTS( "ilbc" , AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
BEGIN_CODECS
CODEC( CODEC_ILBC, Pcm16_2_iLBC, iLBC_2_Pcm16, iLBC_PLC,

@ -52,10 +52,12 @@ static int L16_2_Pcm16(unsigned char* out_buf, unsigned char* in_buf, unsigned i
static unsigned int L16_bytes2samples(long, unsigned int);
static unsigned int L16_samples2bytes(long, unsigned int);
BEGIN_EXPORTS( "l16" )
BEGIN_EXPORTS( "l16" , AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
BEGIN_CODECS
CODEC( CODEC_L16, Pcm16_2_L16, L16_2_Pcm16, NULL, NULL, NULL, L16_bytes2samples, L16_samples2bytes )
CODEC( CODEC_L16, Pcm16_2_L16, L16_2_Pcm16,
AMCI_NO_CODEC_PLC, AMCI_NO_CODECCREATE, AMCI_NO_CODECDESTROY,
L16_bytes2samples, L16_samples2bytes )
END_CODECS
BEGIN_PAYLOADS

@ -80,10 +80,11 @@ void speexNB_destroy(long handle);
static unsigned int speexNB_bytes2samples(long, unsigned int);
static unsigned int speexNB_samples2bytes(long, unsigned int);
BEGIN_EXPORTS("speex")
BEGIN_EXPORTS("speex", AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY)
BEGIN_CODECS
CODEC(CODEC_SPEEX_NB, Pcm16_2_SpeexNB, SpeexNB_2_Pcm16, NULL, speexNB_create, speexNB_destroy,
CODEC(CODEC_SPEEX_NB, Pcm16_2_SpeexNB, SpeexNB_2_Pcm16, AMCI_NO_CODEC_PLC,
speexNB_create, speexNB_destroy,
speexNB_bytes2samples, speexNB_samples2bytes)
END_CODECS

@ -44,11 +44,11 @@
*
* Example declaration:
@code
BEGIN_EXPORTS( "wav" )
BEGIN_EXPORTS( "wav", AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY)
BEGIN_CODECS
CODEC( CODEC_ULAW, Pcm16_2_ULaw, ULaw_2_Pcm16, 0, 0 )
CODEC( CODEC_ALAW, Pcm16_2_ALaw, ALaw_2_Pcm16, 0, 0 )
CODEC( CODEC_ULAW, Pcm16_2_ULaw, ULaw_2_Pcm16, 0, 0, 0, 0, 0 )
CODEC( CODEC_ALAW, Pcm16_2_ALaw, ALaw_2_Pcm16, 0, 0, 0, 0, 0 )
END_CODECS
BEGIN_PAYLOADS
@ -92,11 +92,15 @@ static int Pcm16_2_ALaw( unsigned char* out_buf, unsigned char* in_buf, unsigned
static unsigned int g711_bytes2samples(long, unsigned int);
static unsigned int g711_samples2bytes(long, unsigned int);
BEGIN_EXPORTS( "wav" )
BEGIN_EXPORTS( "wav" , AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
BEGIN_CODECS
CODEC( CODEC_ULAW, Pcm16_2_ULaw, ULaw_2_Pcm16, NULL, NULL, NULL, g711_bytes2samples, g711_samples2bytes )
CODEC( CODEC_ALAW, Pcm16_2_ALaw, ALaw_2_Pcm16, NULL, NULL, NULL, g711_bytes2samples, g711_samples2bytes )
CODEC( CODEC_ULAW, Pcm16_2_ULaw, ULaw_2_Pcm16,
AMCI_NO_CODEC_PLC, AMCI_NO_CODECCREATE, AMCI_NO_CODECDESTROY,
g711_bytes2samples, g711_samples2bytes )
CODEC( CODEC_ALAW, Pcm16_2_ALaw, ALaw_2_Pcm16,
AMCI_NO_CODEC_PLC, AMCI_NO_CODECCREATE, AMCI_NO_CODECDESTROY,
g711_bytes2samples, g711_samples2bytes )
END_CODECS
BEGIN_PAYLOADS

Loading…
Cancel
Save