#include <stdlib.h>
#include <memory.h>
#include "../include/AudioDebug.h"
#include "../include/AudioBuffer.h"
#include "../include/zmalloc.h"
AudioBuffer::
AudioBuffer(
double len,
const char *local_name):
AudioStream(local_name), buflen(len), zflag(0), bufsize(0), bufaddr(0)
{
}
AudioBuffer::
~AudioBuffer()
{
(void) SetSize(0.);
}
Boolean AudioBuffer::
opened() const
{
return (hdrset() && (GetAddress() != 0));
}
#define MIN_ZBUFFER (8192 * 10)
AudioError AudioBuffer::
alloc()
{
long size;
size_t cnt;
unsigned int ncpy;
void* tmpbuf;
size = GetHeader().Time_to_Bytes(GetSize());
cnt = GetByteCount();
AUDIO_DEBUG((5, "%d: AudioBuffer::alloc - change from %d to %d bytes\n",
getid(), cnt, size));
bufsize = 0;
if (size == 0) {
if (bufaddr != 0) {
if (zflag != 0) {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - zfree mmapped buffer\n",
getid()));
(void) zfree((char *)bufaddr);
} else {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - free malloc'd buffer\n",
getid()));
(void) free((char *)bufaddr);
}
zflag = 0;
}
bufaddr = 0;
} else if (size < 0) {
AUDIO_DEBUG((5, "%d: AudioBuffer::alloc - bad size\n",
getid()));
return (RaiseError(AUDIO_ERR_BADARG));
} else if (bufaddr == 0) {
if (size > MIN_ZBUFFER) {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - zmalloc new buffer\n",
getid()));
bufaddr = (void*) zmalloc((unsigned int)size);
zflag = 1;
} else {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - malloc new buffer\n",
getid()));
bufaddr = (void*) malloc((unsigned int)size);
zflag = 0;
}
if (bufaddr == 0) {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - buffer alloc failed\n",
getid()));
return (RaiseError(AUDIO_UNIXERROR));
}
} else {
if ((cnt <= MIN_ZBUFFER) && (size <= MIN_ZBUFFER) &&
(zflag == 0)) {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - realloc to change size\n",
getid()));
bufaddr = (void*)
realloc((char *)bufaddr, (unsigned int)size);
} else {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - zmalloc new buffer\n",
getid()));
tmpbuf = bufaddr;
bufaddr = (void*) zmalloc((unsigned int)size);
if (bufaddr != 0) {
ncpy = (cnt < size) ? (unsigned int)cnt :
(unsigned int)size;
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - trasnfer %d bytes\n",
getid(), ncpy));
(void) memcpy(bufaddr, tmpbuf, ncpy);
}
if ((cnt > MIN_ZBUFFER) && (zflag != 0)) {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - zfree old buffer\n",
getid()));
(void) zfree((char *)tmpbuf);
} else {
AUDIO_DEBUG((5,
"%d: AudioBuffer::alloc - free old buffer\n",
getid()));
(void) free((char *)tmpbuf);
}
zflag = 1;
}
if (bufaddr == 0) {
return (RaiseError(AUDIO_UNIXERROR));
}
}
bufsize = (size_t)size;
return (AUDIO_SUCCESS);
}
void* AudioBuffer::
GetAddress() const
{
return (GetAddress(0.));
}
void* AudioBuffer::
GetAddress(
Double pos) const
{
char *addr;
AudioHdr hdr_local;
AudioHdr(AudioBuffer::*hfunc)()const;
addr = (char *)bufaddr;
if ((addr == 0) || (pos < 0.) || (pos >= buflen))
return (NULL);
if (pos == 0.)
return ((void*) addr);
hfunc = (AudioHdr(AudioBuffer::*)() const)&AudioBuffer::GetHeader;
hdr_local = (this->*hfunc)();
if (hdr_local.Validate())
return (NULL);
addr += hdr_local.Time_to_Bytes(pos);
if (addr >= ((char *)bufaddr + bufsize))
return (NULL);
return ((void*) addr);
}
size_t AudioBuffer::
GetByteCount() const
{
return (bufsize);
}
Double AudioBuffer::
GetSize() const
{
return (buflen);
}
AudioError AudioBuffer::
SetSize(
Double len)
{
if (len == buflen)
return (AUDIO_SUCCESS);
buflen = len;
if (!hdrset()) {
return (AUDIO_SUCCESS);
}
if (buflen < GetLength())
SetLength(buflen);
return (alloc());
}
AudioError AudioBuffer::
SetHeader(
const AudioHdr& h)
{
AudioError err;
err = h.Validate();
if (err)
return (RaiseError(err));
(void) AudioStream::updateheader(h);
if (buflen == 0.)
return (AUDIO_SUCCESS);
if (GetAddress() == 0)
return (alloc());
buflen = h.Bytes_to_Time(GetByteCount());
return (AUDIO_SUCCESS);
}
void AudioBuffer::
SetLength(
Double len)
{
if (!hdrset() || (len < 0.))
return;
if (!opened() && (len > 0.))
return;
if (Undefined(len) || (len > GetSize())) {
setlength(GetSize());
} else {
setlength(len);
}
}
AudioError AudioBuffer::
ReadData(
void* buf,
size_t& len,
Double& pos)
{
off_t resid;
off_t cnt;
off_t offset;
AudioError err;
cnt = (off_t)len;
len = 0;
if (!opened())
return (RaiseError(AUDIO_ERR_NOEFFECT));
if ((pos < 0.) || (cnt < 0))
return (RaiseError(AUDIO_ERR_BADARG));
if (pos >= GetLength()) {
err = AUDIO_EOF;
err.sys = AUDIO_COPY_INPUT_EOF;
return (err);
}
offset = GetHeader().Time_to_Bytes(pos);
resid = GetHeader().Time_to_Bytes(GetLength()) - offset;
if (resid <= 0) {
err = AUDIO_EOF;
err.sys = AUDIO_COPY_INPUT_EOF;
return (err);
}
if (cnt > resid)
cnt = resid;
err = AUDIO_SUCCESS;
if (GetHeader().Bytes_to_Bytes(cnt) > 0) {
memcpy((char *)buf, (char *)((off_t)GetAddress() + offset),
(int)cnt);
} else {
err.sys = AUDIO_COPY_ZERO_LIMIT;
}
len = (size_t)cnt;
pos = GetHeader().Bytes_to_Time(offset + cnt);
coerceEndian((unsigned char *)buf, len, localByteOrder());
return (err);
}
AudioError AudioBuffer::
WriteData(
void* buf,
size_t& len,
Double& pos)
{
off_t resid;
off_t cnt;
off_t offset;
AudioError err;
cnt = (off_t)len;
len = 0;
if (!opened())
return (RaiseError(AUDIO_ERR_NOEFFECT));
if ((pos < 0.) || (cnt < 0))
return (RaiseError(AUDIO_ERR_BADARG));
if (pos >= GetSize()) {
err = AUDIO_EOF;
err.sys = AUDIO_COPY_OUTPUT_EOF;
return (err);
}
offset = GetHeader().Time_to_Bytes(pos);
resid = (off_t)bufsize - offset;
if (resid <= 0) {
err = AUDIO_EOF;
err.sys = AUDIO_COPY_OUTPUT_EOF;
return (err);
}
if (cnt > resid)
cnt = resid;
err = AUDIO_SUCCESS;
if (GetHeader().Bytes_to_Bytes(cnt) > 0) {
memcpy((char *)((off_t)GetAddress() + offset), (char *)buf,
(int)cnt);
} else {
err.sys = AUDIO_COPY_ZERO_LIMIT;
}
len = (size_t)cnt;
pos = GetHeader().Bytes_to_Time(offset + cnt);
setlength(pos);
return (err);
}
AudioError AudioBuffer::
AppendData(
void* buf,
size_t& len,
Double& pos)
{
Double local_length;
AudioError err;
if (!hdrset())
return (RaiseError(AUDIO_ERR_NOEFFECT));
if (pos < 0.)
return (RaiseError(AUDIO_ERR_BADARG));
local_length = pos + GetHeader().Bytes_to_Time(len);
if (local_length > GetSize()) {
err = SetSize(local_length);
if (err != AUDIO_SUCCESS)
return (err);
}
return (WriteData(buf, len, pos));
}
AudioError AudioBuffer::
AsyncCopy(
Audio* to,
Double& frompos,
Double& topos,
Double& limit)
{
caddr_t bptr;
size_t cnt;
size_t svcnt;
Double svfrom;
Double svto;
Double lim;
AudioHdr tohdr;
AudioError err;
if (!opened())
return (RaiseError(AUDIO_ERR_NOEFFECT));
tohdr = to->GetHeader();
if (limit < 0.)
return (RaiseError(AUDIO_ERR_BADARG));
svfrom = GetLength();
if (frompos >= svfrom) {
limit = 0.;
err = AUDIO_EOF;
err.sys = AUDIO_COPY_INPUT_EOF;
return (err);
}
lim = svfrom - frompos;
if (!Undefined(limit) && (limit < lim))
lim = limit;
limit = 0.;
bptr = (caddr_t)GetAddress(frompos);
if (bptr == 0) {
err = AUDIO_EOF;
err.sys = AUDIO_COPY_INPUT_EOF;
return (err);
}
cnt = (size_t)GetHeader().Time_to_Bytes(lim);
if (cnt == 0) {
err = AUDIO_SUCCESS;
err.sys = AUDIO_COPY_ZERO_LIMIT;
return (err);
}
svcnt = (size_t)GetAddress() + (size_t)GetByteCount();
if ((bptr + cnt) > (caddr_t)svcnt) {
cnt = (size_t)((caddr_t)svcnt - bptr);
}
if (GetHeader().Bytes_to_Bytes(cnt) == 0) {
err = AUDIO_EOF;
err.sys = AUDIO_COPY_INPUT_EOF;
return (err);
}
svfrom = frompos;
svto = topos;
svcnt = cnt;
err = to->WriteData(bptr, cnt, topos);
limit = topos - svto;
frompos = svfrom + limit;
if (!err && (cnt < svcnt)) {
err.sys = AUDIO_COPY_SHORT_OUTPUT;
}
return (err);
}