[asterisk-dev] playback application sends a short frame at endof file
Paul Albrecht
albrecht at glccom.com
Mon Jul 30 11:44:44 CDT 2012
On Mon, 2012-07-30 at 10:49 -0500, Kevin P. Fleming wrote:
> On 07/30/2012 10:32 AM, Paul Albrecht wrote:
>
> > The playback application sends a short frame at the end of file if the
> > sound file isn't a multiple of the 160 of samples. Is that a bug or a
> > feature?
>
> Neither. It is sending what it was told to send. If your endpoints are
> particular about receiving consistently-sized frames, then you'll need
> to pad your recording files to an appropriate size. This can be tricky,
> though, since channels can negotiate varying frame sizes, and finding a
> multiple that makes sense for all of them might be more work than you'd
> care to do.
>
> In the end, though, it should not matter: any reasonably well
> implemented endpoint will accept variable-sized frames, as long as they
> aren't any larger than what it has stated its maximum to be (if it did so).
Padding the file out to a packet boundary was my first thought. However,
when I looked through the asterisk code, it didn't make sense. The first
example I looked at was slinear, but I think all the fixed rate codecs
are coded essentially the same way.
Here's the code for slinear:
#define BUF_SIZE 320 /* 320 bytes, 160 samples */
#define SLIN_SAMPLES 160
static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext)
{
int res;
/* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_SLINEAR;
s->fr.mallocd = 0;
AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL;
}
*whennext = s->fr.samples = res/2;
s->fr.datalen = res;
return &s->fr;
}
As I read the code, the log message is unreachable which is probably not
what the coder intended.
A better way to detect the end of the file is to reverse the arguments
to the fread. Instead of reading buf_size objects of size byte, read one
object of buf_size. That way you know you're at end of file when you
read the short frame. Since you don't need the short frame, simply
discard it though I suppose you could pad it to packet size.
Here's the updated code:
static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext)
{
int res;
/* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_SLINEAR;
s->fr.mallocd = 0;
AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
if (!(res = fread(s->fr.data, s->fr.datalen, 1, s->f))) {
return NULL;
}
*whennext = s->fr.samples = SLIN_SAMPLES;
s->fr.datalen = BUF_SIZE;
return &s->fr;
}
>
--
Paul Albrecht
More information about the asterisk-dev
mailing list